Floating point 当55.8/9.3=6时,为什么fmod(55.8,9.3)返回9.3?

Floating point 当55.8/9.3=6时,为什么fmod(55.8,9.3)返回9.3?,floating-point,number-theory,Floating Point,Number Theory,我正在尝试使用fmod函数,但没有得到预期的结果 由于浮点不精确,它实际上返回9.299999994。55.8或9.3都不能精确表示为基数为2的浮点数 这是一个非常普遍的问题。一个很好的参考是。由于浮点不精确,它实际上返回9.299999994。55.8或9.3都不能精确表示为基数为2的浮点数 这是一个非常普遍的问题。一个很好的参考是。像大多数小数一样,这些数字不能精确地表示为二进制浮点值。假设最常见的double,实际值约为: 55.799999999999997158 9.29999999

我正在尝试使用fmod函数,但没有得到预期的结果

由于浮点不精确,它实际上返回9.299999994。55.8或9.3都不能精确表示为基数为2的浮点数


这是一个非常普遍的问题。一个很好的参考是。

由于浮点不精确,它实际上返回9.299999994。55.8或9.3都不能精确表示为基数为2的浮点数


这是一个非常普遍的问题。一个很好的参考是。

像大多数小数一样,这些数字不能精确地表示为二进制浮点值。假设最常见的
double
,实际值约为:

55.799999999999997158
9.2999999999999936051
以及:

这些不完全分开,并且
fmod
的结果大约为:

55.799999999999997158
9.2999999999999936051
当显示到小数点后的小数位时,将四舍五入到
9.3

这些值是由以下C++程序产生的:

#include <iostream>
#include <iomanip>
#include <cmath>

int main()
{
    std::cout << std::setprecision(20);

    double a = 55.8;
    double b = 9.3;

    std::cout << a << std::endl;
    std::cout << b << std::endl;
    std::cout << fmod(a,b) << std::endl;
}
#包括
#包括
#包括
int main()
{

std::cout与大多数十进制分数一样,这些数字不能精确地表示为二进制浮点值。假设最常见的
double
,实际值大约为:

55.799999999999997158
9.2999999999999936051
以及:

这些不完全分开,并且
fmod
的结果大约为:

55.799999999999997158
9.2999999999999936051
当显示到小数点后的小数位时,将四舍五入到
9.3

这些值是由以下C++程序产生的:

#include <iostream>
#include <iomanip>
#include <cmath>

int main()
{
    std::cout << std::setprecision(20);

    double a = 55.8;
    double b = 9.3;

    std::cout << a << std::endl;
    std::cout << b << std::endl;
    std::cout << fmod(a,b) << std::endl;
}
#包括
#包括
#包括
int main()
{

std::cout事实上,你期望它在6附近,这意味着你的问题不是你不理解舍入,而是你不知道fmod
实际上做了什么

fmod
是除法的整数,而不是商。也就是说,它是减去除法的整数副本后剩余的量。在数学术语中,
a=q*b+r
,其中
q=int(a/b)
,和
r=fmod(a,b)

如果a和b正好是55.8和9.3,a/b正好是6,剩下的是0。因此,你完全有理由期望结果为0,在某些平台上,这可能是你实际得到的结果

然而,在大多数平台上,最接近55.8和9.3的近似值分别约为55.7999999997158和9.3000000000000007105(原因见Mark Ransom的答案),表示商为5.999999999999,表示商的整数部分为5,表示余数为55.799999999997158-9.30000000000000007105*5=9.2999999997,显示为9.3


如果你仔细想想,这是有道理的。如果右余数是0,一个小的舍入误差不能使余数为1或6;实际上,所有可能的情况是非常接近0或非常接近9.3的某个数字。(如果有帮助,请考虑模9.3算术,其中0和9.3是相同的数字。)事实上,你期望它在6附近,这意味着你的问题不是你不理解四舍五入,而是你不知道fmod实际做了什么

fmod
是除法的整数,而不是商。也就是说,它是减去除法的整数副本后剩余的量。在数学术语中,
a=q*b+r
,其中
q=int(a/b)
,和
r=fmod(a,b)

如果a和b正好是55.8和9.3,a/b正好是6,剩下的是0。因此,你完全有理由期望结果为0,在某些平台上,这可能是你实际得到的结果

然而,在大多数平台上,最接近55.8和9.3的近似值分别约为55.7999999997158和9.3000000000000007105(原因见Mark Ransom的答案),表示商为5.999999999999,表示商的整数部分为5,表示余数为55.799999999997158-9.30000000000000007105*5=9.2999999997,显示为9.3


如果你仔细想想,这是有道理的。如果右余数是0,一个小的舍入误差不能使余数为1或6;实际上,所有可能的情况是非常接近0或非常接近9.3的某个数字。(如果有帮助,请考虑模9.3算术,其中0和9.3是相同的数字。)

请每个问题使用一种语言我怀疑这是浮点舍入问题。这些数字都不能精确表示为浮点。请每个问题使用一种语言我怀疑这是浮点舍入问题。这两个数字都不能精确表示为浮点。不能准确表示是一回事,但h这会不会导致小数字的差值超过3?@Cubic,
fmod
返回除法的剩余部分。在这种情况下,除法返回5而不是6,因为55.8被向下舍入,或者9.3被向上舍入。我确信这个fmod的预期结果是0.0…请注意,解决方案是添加一个模糊因子(或“公差”(如果您愿意),在执行模运算之前,就像您在测试相等性时总是需要指定一个模糊因子一样。如果模糊因子是
ε
,那么您应该测试
fmod(55.8+ε,9.3)<2ε
,以查看结果是否为“零”。"@Potatoswatter:对于使用fmod函数的浮点问题,这不是一个很好的解决方案。举个例子,它在这种情况下不起作用,因为fmod返回的数字略低于9.3,所以测试它是否低于一个小ε的两倍将产生
false
,但询问者显然期望
true
.@MarkRansom:缩放第一个操作数会增加相对于第二个操作数的错误,这可能更为关键(例如,在减少周期函数的参数时)。事实上,对于连续周期函数,第二个操作数的哪一侧