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)

Sollya and Octave 定义为:

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

godbolt example


所以回答你的问题:这不是错误,这是预期的行为。
这些函数只是在 C++ 中以不同的方式命名(尽管命名方案有点混乱)