GCC mod() 定义
GCC mod() definition
我正在使用 GCC(使用 -O3 -ffast-math 编译)在 C++ 中创建更快的 mod(x,2) 函数,并发现 GCC 和 Octave 之间的结果差异:
float fast_fmod2(float x){ // over 50x faster than std::fmod(x, 2.0f)
x *= 0.5f;
return 2.0f * ( x - std::floor(x));
}
结果(mod(输入,2.0f)):
Input : -7.8539786
std::fmod() : -1.853978633881
Octave mod(): 0.146021366119
fast_fmod2 : 0.146021366119
...
Input : 7.8539805
std::fmod() : 1.853980541229
Octave mod(): 1.853980541229
fast_fmod2 : 1.853980541229
我也检查了其他几个数学软件,看起来至少 Sollya 和 Wolfram|Alpha 支持 Octave 结果,并且之前提到的记录了与 Octave 相同的函数定义。
GCC 将 mod 函数定义为:
mod(A, P) = A - (int(A/P) * P)
mod(a, b) = a - (b * floor(a / b))
由于 int(a/b) 与 floor(a/b) 的舍入不同,GCC 定义给出了负 A 的不同答案。
>> int16(-2.19/2)
ans = -1
>> floor(-2.19/2)
ans = -2
是 GCC 版本的错误还是其他原因导致的差异?
我假设你的意思是 std:fmod
而不是 std::mod
(官方 c++ 标准中没有 std::mod
)
造成这种差异的原因是 std::fmod
并不像您想象的那样。
std::fmod
计算余数,不是算术模数。
Computes the floating-point remainder of the division operation x
/y
如果你想要算术模数,你需要使用 std::remainder
代替:
Computes the IEEE remainder of the floating point division operation x
/y
.
The IEEE floating-point remainder of the division operation x/y
calculated by this function is exactly the value x - n*y
, where the value n
is the integral value nearest the exact value x/y
. When |n-x/y| = ½
, the value n
is chosen to be even.
这将在您的示例中产生预期的结果:
std::cout << std::remainder(-7.8539786f, 2.0f) << std::endl; // 0.146021
所以回答你的问题:这不是错误,这是预期的行为。
这些函数只是在 C++ 中以不同的方式命名(尽管命名方案有点混乱)
- 八度
mod
== C++ std::reminder
- 八度
rem
== C++ std::fmod
我正在使用 GCC(使用 -O3 -ffast-math 编译)在 C++ 中创建更快的 mod(x,2) 函数,并发现 GCC 和 Octave 之间的结果差异:
float fast_fmod2(float x){ // over 50x faster than std::fmod(x, 2.0f)
x *= 0.5f;
return 2.0f * ( x - std::floor(x));
}
结果(mod(输入,2.0f)):
Input : -7.8539786
std::fmod() : -1.853978633881
Octave mod(): 0.146021366119
fast_fmod2 : 0.146021366119
...
Input : 7.8539805
std::fmod() : 1.853980541229
Octave mod(): 1.853980541229
fast_fmod2 : 1.853980541229
我也检查了其他几个数学软件,看起来至少 Sollya 和 Wolfram|Alpha 支持 Octave 结果,并且之前提到的记录了与 Octave 相同的函数定义。
GCC 将 mod 函数定义为:
mod(A, P) = A - (int(A/P) * P)
mod(a, b) = a - (b * floor(a / b))
由于 int(a/b) 与 floor(a/b) 的舍入不同,GCC 定义给出了负 A 的不同答案。
>> int16(-2.19/2)
ans = -1
>> floor(-2.19/2)
ans = -2
是 GCC 版本的错误还是其他原因导致的差异?
我假设你的意思是 std:fmod
而不是 std::mod
(官方 c++ 标准中没有 std::mod
)
造成这种差异的原因是 std::fmod
并不像您想象的那样。
std::fmod
计算余数,不是算术模数。
Computes the floating-point remainder of the division operation
x
/y
如果你想要算术模数,你需要使用 std::remainder
代替:
Computes the IEEE remainder of the floating point division operation
x
/y
. The IEEE floating-point remainder of the division operationx/y
calculated by this function is exactly the valuex - n*y
, where the valuen
is the integral value nearest the exact valuex/y
. When|n-x/y| = ½
, the valuen
is chosen to be even.
这将在您的示例中产生预期的结果:
std::cout << std::remainder(-7.8539786f, 2.0f) << std::endl; // 0.146021
所以回答你的问题:这不是错误,这是预期的行为。
这些函数只是在 C++ 中以不同的方式命名(尽管命名方案有点混乱)
- 八度
mod
== C++std::reminder
- 八度
rem
== C++std::fmod