【问题标题】:c#: sum of two double numbers problem [duplicate]c#:两个双数之和问题[重复]
【发布时间】:2011-03-22 09:04:28
【问题描述】:

可能重复:
Why is floating point arithmetic in C# imprecise?

嗨。我有以下问题:

43.65+61.11=104.75999999999999

对于小数是正确的:

(decimal)43.65+(decimal)61.11=104.76

为什么 double 的结果是错误的?

【问题讨论】:

  • 处理double not bing 无法表示所有数字的问题有很多问题。如果您搜索c# and double,您会发现不少。这个很好,例如:Why is (double)0.6f > (double)(6/10f)?。另外,Jon Skeet's article 值得一读。
  • 您不需要转换为十进制。只需使用“m”后缀即可。例如,43.6m + 61.11m 将两种文字都标识为“十进制类型值”。

标签: c# double decimal


【解决方案1】:

这个问题及其答案是关于这方面的大量信息 - Difference between decimal, float and double in .NET?

引用:

  • 对于“自然准确”的值 小数”最好使用小数。 这通常适用于任何 人类发明的概念:金融 价值观是最明显的例子, 但也有其他人。考虑 给潜水员或溜冰者的分数, 例如。

  • 对于更多的人工制品值 无法真正测量的性质 无论如何,float/double 更多 合适的。例如,科学 数据通常表示为 这种形式。这里,原始值 开始时不会“精确到十进制” ,所以它对 预期结果保持 “小数精度”。浮动二进制 点类型的工作速度要快得多 小于小数。

【讨论】:

    【解决方案2】:

    简短回答:浮点表示(例如“double”)本质上是不准确的。定点也是如此(例如“十进制”),但定点表示的不准确性是另一种类型。这里有一个简短的解释:http://effbot.org/pyfaq/why-are-floating-point-calculations-so-inaccurate.htm

    您可以在 google 上搜索“浮点不准确”等更多信息。

    【讨论】:

      【解决方案3】:

      这并没有完全错。它是最接近求和结果的二进制浮点数的十进制表示。

      问题在于 IEEE 浮点数不能准确表示 43.65 + 61.11,因为使用了二进制尾数。某些系统(例如 Python 2.7 和 Visual C++ 的标准 I/O 库)将四舍五入到解析为相同二进制的最简单十进制,并打印预期的 104.76。但所有这些系统在内部都得出完全相同的答案。

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

      【讨论】:

        【解决方案4】:

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

        请参阅here 了解一些简单的阅读内容:)

        【讨论】:

        • 小数是分数。问题是典型的机器表示是二进制表示,不能用有限展开来表示所有小数。
        • 十进制是货币类型的最佳选择
        【解决方案5】:

        这归结为浮点数存储为二进制浮点数的事实,就像在基数 10 中一样,有些数字如果不截断就无法存储。以 10 进制中的 1/3 为例,即 0.3 循环。当转换为二进制时,您正在处理的数字是重复出现的。

        我不同意浮点数或双精度数或多或少比十进制表示更准确。它们与您选择的精度一样准确。但是,它们是不同的表示形式,并且可以完全表示不同的数字而不是以 10 为基数。

        Decimal 以 10 为基数存储数字。这可能会给您预期的结果

        【讨论】:

          【解决方案6】:

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

          IEEE-754 Binary numbers cannot calculate with .1 or .01 准确。所以浮点格式化近似输入,然后你得到近似输出,这是完全可以接受的浮点被设计来处理——物理模拟、科学数据和快速数值数学方法。

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

          #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\n", g, e, m);
              return 0;
          }
          
          $ ./fp
          0.0100000007078051567077636718750000000000,
          0.0100000000000000019428902930940239457414,
          0.0100000000000000011102569059430467124372
          

          所有三种可能性都没有给出确切的答案,0.01,但它们给出的数字确实非常接近答案。

          但货币使用十进制算术。

          【讨论】:

          • 二进制数可以准确地表示0.1或0.000000000000001。阅读定点表示,然后阅读浮点表示,然后回答这些问题。
          【解决方案7】:

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

          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

          class Program
          {
              static void Main(string[] args)
              {
                  float d1 = 43.65f;
                  float d2 = 61.11f;
                  double d3 = d1 + d2;
                  Console.WriteLine(d3);
                  Console.ReadLine();
              }
          }
          

          检查您是否正在从浮点数转换为双精度数,这可能会导致此问题。

          【讨论】:

            猜你喜欢
            • 2013-09-07
            • 2011-12-21
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2023-03-05
            • 1970-01-01
            • 2020-06-08
            • 2021-08-09
            相关资源
            最近更新 更多