c++ fmod 对于 fmod(0.6,0.2) 返回 0.2

问题描述 投票:0回答:4

当我在 c++ 中使用 fmod(0.6,0.2) 时,它返回 0.2

我知道这是由浮点精度引起的,但看来我此时必须获得两个双精度数的余数

非常感谢此类问题的任何解决方案

c++ floating-accuracy fmod
4个回答
3
投票

数学值

0.6
0.2
无法用二进制浮点数精确表示。

这个演示程序将向您展示发生了什么:

#include <iostream>
#include <iomanip>
#include <cmath>
int main() {
    const double x = 0.6;
    const double y = 0.2;
    std::cout << std::setprecision(60)
              << "x          = " << x << "\n"
              << "y          = " << y << "\n"
              << "fmod(x, y) = " << fmod(x, y) << "\n";
}

我的系统(很可能在你的系统上)的输出是:

x          = 0.59999999999999997779553950749686919152736663818359375
y          = 0.200000000000000011102230246251565404236316680908203125
fmod(x, y) = 0.1999999999999999555910790149937383830547332763671875

根据您传递的参数,

fmod()
返回的结果是正确的。

如果您需要其他结果(我想您正在期待

0.0
),您将不得不做一些不同的事情。有多种可能性。您可以检查结果是否与
0.2
存在很小的差异,或者您可以使用整数算术进行计算(例如,如果您正在处理的所有数字都是
0.1
 的倍数) 0.01
)。


1
投票

我认为最好的选择是使用余数函数而不是 fmod。对于给定的示例,它将返回一个非常小的数字,而不是 0.2。您可以利用这一事实,通过四舍五入到一定的精度级别来假设余数为 0。


0
投票

你是对的,问题是舍入错误。试试这个代码:

#include <stdio.h>
#include <math.h>
int main()
{
    double d6 = 0.6;
    double d2 = 0.2;
    double d = fmod (d6, d2);
    printf ("%30.20e %30.20e %30.20e\n", d6, d2, d);

}

当我在 gcc 4.4.7 中运行它时,输出是:

5.99999999999999977796e-01     2.00000000000000011102e-01     1.99999999999999955591e-01

至于如何“修复”它,我不太清楚你到底想做什么,不知道该建议什么。总会有一些数字无法用浮点精确表示,所以这种行为是不可避免的。

有关问题领域的更多信息将有助于获得更好的建议。例如,如果您正在使用的数字始终只有小数点后一位数字,并且足够小,则只需乘以 10,四舍五入到最接近的整数(或 long 或 long long),然后使用 % 运算符而不是fmod 函数。如果您想查看 fmod 的结果是否为 0.0,只需接受接近 0.2 的结果(在本例中),就好像它接近 0 一样。


0
投票

这不是一个真正的解决方案,而是一个简单的解决方法。 Matlab 的文档中有一个简单的公式,它显示了它的 mod 函数如何几乎正确地计算浮点模(我的意思是尽管存在浮点错误,但它非常接近预期结果。)。该公式仅由几个浮点运算组成:

x - y * floor(x / y)

这是一个带有一些测试用例的小程序。

#include <stdio.h>

#define _USE_MATH_DEFINES
#include <math.h>
#include <fenv.h>
#include <float.h>

static inline double mod(double x, double y)
{
    return  x - y * floor(x / y);
}

double test_parameters[][3] = 
{ 
    { 1.0, 0.3, 1.0 }, 
    { 10.0, 0.0002, 0.0 }, 
    { 5.0, 2.0, 1.0 }, 
    { 6.1, 3.0, 0.1 }, 
    { 1.0, 0.7, 0.3 }, 
};

int main()
{
    for (size_t i = 0; i < sizeof(test_parameters) / sizeof(test_parameters[0]); i++)
    {
        double x = test_parameters[i][0];
        double y = test_parameters[i][1];
        double e = test_parameters[i][2];
        double m = mod(x, y);

        printf("mod(%lf, %lf) == %lf: %s\n", x, y, m,  m - e < DBL_EPSILON ? "true": "false");
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.