输出fmod函数c ++

时间:2016-10-10 20:25:17

标签: c++ floating-point fmod

假设:

#include <iostream>
#include <cmath>
#include <limits>
using namespace std;

int main() {
    // your code goes here
    double h = .1;
    double x = 1;
    int nSteps = abs(x / h);

    double rem = fmod(x, h);
    cout<<"fmod output is "<<rem<<endl;
    if(abs(rem)<std::numeric_limits<double>::epsilon())
        cout<<"fmod output is almost near 0"<<endl;

    rem = remainder(x,h);
    cout<<"remainder output is "<<rem<<endl;
    if(abs(rem)<std::numeric_limits<double>::epsilon())
        cout<<"remainder output is almost near 0"<<endl;

    return 0;
}

鉴于int(x/h) == 10,我原本期望fmod()结果接近0,但我得到的是.0999999999。这是一个显着的差异。余数()的结果似乎仍然可以接受。可以在http://ideone.com/9wBlva

处尝试使用代码

为什么fmod()的结果有显着差异?

1 个答案:

答案 0 :(得分:3)

您遇到的问题是,您使用的fmod版本似乎遵循cppreference定义的实施方式:

double fmod(double x, double y)
{
    double result = std::remainder(std::fabs(x), (y = std::fabs(y)));
    if (std::signbit(result)) result += y;
    return std::copysign(result, x);
} 

std::remainder计算一个非常小的结果,几乎为零(-5.55112e-17使用1和0.1为我,-1.11022e-16为2和0.2)。但是,重要的是结果是否定,这意味着std::signbit返回true,导致y被添加到结果中,从而有效地使结果相等到y

请注意,std::fmod的文档没有说明使用std::remainder的内容:

  

由此函数计算的除法运算x / y的浮点余数恰好是值x - n * y,其中n是x / y,其小数部分被截断。

因此,如果您自己计算该值,则最终会得到零(即使您对结果使用std::round而不是纯整数截断)

x为2且y为0.2

时,我们会发现类似的问题
double x = 2;
double y = .2;

int n = static_cast<int>(x/y);
double result = x - n*y;
std::cout << "Manual: " << result << std::endl;
std::cout << "fmod: " << std::fmod(x,y) << std::endl;

输出(gcc demo

  

手册:0
  fmod:0.2

然而问题并没有降到只有gcc;我也在MSVC和clang中看到它。在clang中,如果使用float而不是double,则有时会有不同的行为。

来自std::remainder的这个非常小的负值来自这样一个事实:在浮点数学中,0.1和0.2都不能完全表示。如果你将x和y改为2和0.25,那么一切都很好。