【问题标题】:Why is floating point arithmetic in C# imprecise?为什么 C# 中的浮点运算不精确?
【发布时间】:2009-04-15 22:12:57
【问题描述】:

为什么下面的程序会打印它打印的内容?

class Program
{
    static void Main(string[] args)
    {
        float f1 = 0.09f*100f;
        float f2 = 0.09f*99.999999f;

        Console.WriteLine(f1 > f2);
    }
}

输出是

false

【问题讨论】:

标签: c# floating-point


【解决方案1】:

浮点只有这么多位精度。如果您看到 f1 == f2,那是因为任何差异都需要比 32 位浮点数所能表示的更高的精度。

我推荐阅读What Every Computer Scientist Should Read About Floating Point

【讨论】:

  • +1 为什么,为什么我在点击提交按钮后看到有人发布了链接? :P
  • +1 msdn.microsoft.com/en-us/library/b1e65aza(VS.71).aspx Michael 是正确的,C# float 只有 7 位精度,而 99.999999f 有 8 位。
  • 这不是 C# 特定的。单精度 IEEE-754 浮点数将只有 32 位,它提供大约 7 个十进制数字的精度。如果您想要更好,请使用双倍。
  • 双打只是将问题推到更多位。您真正想要的是 QD 库中的四倍双打(请参阅crd.lbl.gov/~dhbailey/mpdist)。那里也有一个任意精度库。
【解决方案2】:

在这种特殊情况下,这是因为 .09 和 .999999 不能以二进制精确表示(类似地,1/3 不能以十进制精确表示)。例如,0.111111111111111111101111基座2是0.999998986721038818359375基座10添加1到先前二进制值,0.11111111111111111111基座2是0.99999904632568359375基座10没有用于恰好0.999999的二进制值。浮点精度还受到分配用于存储指数和尾数小数部分的空间的限制。此外,和整数类型一样,浮点数可以溢出其范围,尽管它的范围大于整数范围。

在 Xcode 调试器中运行这段 C++ 代码,

float myFloat = 0.1;

显示 myFloat 的值为 0.100000001。它关闭了 0.000000001。不是很多,但是如果计算有几个算术运算,那么不精确可能会更加复杂。

恕我直言,浮点数的一个很好的解释是在 Introduction to Computer Organization with x86-64 Assembly Language & GNU/Linux 的第 14 章中,作者是加利福尼亚州立大学索诺玛分校的 Bob Plantz(已退休)@ 987654321@。以下内容基于该章节。

浮点类似于科学记数法,其中一个值存储为大于或等于 1.0 且小于 2.0(尾数)的混合数,乘以另一个数的某个幂(指数)。浮点使用基数 2 而不是基数 10,但在 Plantz 给出的简单模型中,为了清楚起见,他使用基数 10。想象一个系统,其中两个存储位置用于尾数,一个位置用于指数*的符号(0 表示 +,1 表示 -),一个位置用于指数。现在添加 0.93 和 0.91。答案是 1.8,而不是 1.84。

9311 表示 0.93,即 -1 的 9.3 倍 10。

9111 表示 0.91,即 -1 的 9.1 乘以 10。

确切的答案是 1.84,或 1.84 乘以 10 到 0,如果我们有 5 个位置,这将是 18400,但是,只有四个位置,答案是 1800,或者 1.8 乘以 10 到零,或者 1.8。当然,浮点数据类型可以使用四个以上的存储位置,但是位置的数量还是有限的。

不仅精度受空间限制,而且“二进制小数值的精确表示仅限于 2 的逆幂之和。” (Plantz, op. cit.)。

0.11100110(二进制)= 0.89843750(十进制)

0.11100111(二进制)= 0.90234375(十进制)

二进制中没有十进制 0.9 的精确表示。即使将分数从更多位置取出也行不通,因为您会在右侧永远重复 1100。

初级程序员通常认为浮点运算更重要 比整数更准确。确实,即使添加两个非常大的 整数会导致溢出。乘法使它更有可能 结果将非常大,因此会溢出。并且在使用时 对于两个整数,C/C++ 中的 / 运算符导致小数部分 丢失。但是,...浮点表示有自己的 一组不准确。 (Plantz, op. cit.)

*在浮点中,数字的符号和指数的符号都被表示。

【讨论】:

    【解决方案3】:

    主要的是这不仅仅是.Net:它是内存中underlying system most every language will use to represent a float 的限制。精度只能到此为止。

    当您考虑到它甚至不是以十为底的数字时,您也可以使用相对简单的数字来获得一些乐趣。例如,0.1(1/10th)以二进制表示时是重复的小数,就像以十进制表示时 1/3rd 一样。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-11-22
      • 2019-11-08
      • 2021-12-06
      • 2010-10-22
      • 2022-01-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多