c#:两个双数问题的总和

c#: sum of two double numbers problem

本问题已经有最佳答案,请猛点这里访问。

Possible Duplicate:
Why is floating point arithmetic in C# imprecise?

你好。我有以下问题:

1
43.65+61.11=104.75999999999999

小数正确:

1
(decimal)43.65+(decimal)61.11=104.76

为什么加倍的结果是错误的?


这个问题及其答案是关于这个的大量信息-在.NET中十进制、浮点和双精度之间的差异?

引述:

  • For values which are"naturally exact
    decimals" it's good to use decimal.
    This is usually suitable for any
    concepts invented by humans: financial
    values are the most obvious example,
    but there are others too. Consider the
    score given to divers or ice skaters,
    for example.

  • For values which are more artefacts of
    nature which can't really be measured
    exactly anyway, float/double are more
    appropriate. For example, scientific
    data would usually be represented in
    this form. Here, the original values
    won't be"decimally accurate" to start
    with, so it's not important for the
    expected results to maintain the
    "decimal accuracy". Floating binary
    point types are much faster to work
    with than decimals.


简短回答:浮点表示(如"double")本质上是不准确的。定点(如"小数")也是如此,但定点表示的不准确度是另一类。下面是一个简短的解释:http://effbot.org/pyfaq/why-are-floating-point-calculations-so-unaccurance.htm

你可以谷歌搜索"浮点不准确"或更多。


这并不完全是错的。它是与求和得到的二进制浮点数最接近的十进制表示。

问题是,由于使用了二进制尾数,所以ieee float不能精确地表示43.65+61.11。一些系统(如Python 2.7和VisualC++的标准I/O库)将绕过最简单的十进制,解析为相同的二进制,并打印预期的104.76。但所有这些系统在内部都得到了完全相同的答案。

有趣的是,十进制符号可以有限地表示任何有限的二进制分数,而相反的则不成立。如果人类有两个手指,计算机使用十态存储器,我们就不会有这个问题。-)


归根结底,浮点数是以二进制浮点数的形式存储的,和以10为基数的浮点数一样,有些数字在没有截断的情况下是无法存储的。以10为基数的1/3为例,即.3循环。当转换为二进制时,您要处理的数字是循环出现的。

我不同意浮点或双精度比十进制表示更准确或更不准确。它们和你选择的精度一样精确。然而,它们是一种不同的表示,不同的数字可以表示为整数,而不是以10为基数。

十进制以10为基数存储数字。这可能会给你预期的结果


因为double使用分数模型。任何小于1的数字都以x/y的形式表示。鉴于此信息,有些数字只能近似。使用十进制,而不是双精度计算。

请看这里了解一些光读数:)


十进制算术非常适合以10为基数的数字表示,因为10为基数的数字可以精确地以十进制表示。(这就是为什么货币总是以适当的货币类别存储,或存储在int中,并带有表示"便士"或"便士"或其他类似的十进制货币的比例系数。)

ieee-754二进制数不能用.1.01精确计算。所以浮点格式近似输入,你得到的是近似输出,这对于浮点被设计用来处理的东西是完全可以接受的——物理模拟、科学数据和快速的数值数学方法。

注意这个简单的程序和输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <stdio.h>

int main(int argc, char* argv[]) {
    float f, g;
    double d, e;
    long double l, m;

    f=0.1;
    g=f*f;
    d=0.1;
    e=d*d;
    l=0.1;
    m=l*l;
    printf("%40.40f, %40.40f, %40.40Lf
"
, g, e, m);
    return 0;
}

$ ./fp
0.0100000007078051567077636718750000000000,
0.0100000000000000019428902930940239457414,
0.0100000000000000011102569059430467124372

这三种可能性都不能给出准确的答案,0.01,但它们给出的数字与答案非常接近。

但对货币使用十进制算术。


真的?下面的代码按预期返回104.76:

1
2
3
4
5
6
7
8
9
10
11
class Program
{
    static void Main(string[] args)
    {
        double d1 = 43.65;
        double d2 = 61.11;
        double d3 = d1 + d2;
        Console.WriteLine(d3);
        Console.ReadLine();
    }
}

鉴于以下代码返回104.76000213623

1
2
3
4
5
6
7
8
9
10
11
class Program
{
    static void Main(string[] args)
    {
        float d1 = 43.65f;
        float d2 = 61.11f;
        double d3 = d1 + d2;
        Console.WriteLine(d3);
        Console.ReadLine();
    }
}

检查是否正在从float转换为double,这可能导致此问题。