首页 > 解决方案 > 浮点精度中double和float的区别

问题描述

在阅读了这个问题和这个msdn 博客之后,我尝试了几个例子来测试这个:

Console.WriteLine(0.8-0.7 == 0.1);

是的,预期的输出是False. 因此,我尝试将两边的表达式转换为doublefloat查看是否可以获得不同的结果:

Console.WriteLine((float)(0.8-0.7) == (float)(0.1));
Console.WriteLine((double)(0.8-0.7) == (double)(0.1));

第一行输出True但是第二行输出False,为什么会这样?

此外,

Console.WriteLine(8-0.7 == 7.3);
Console.WriteLine(8.0-0.7 == 7.3);

True即使没有强制转换,上面的两条线也会给出。和 ...

Console.WriteLine(18.01-0.7 == 17.31);

此行输出False。如果它们都被浮点数减去,减去 18.01 如何减去 8 差?

我试图通读博客和问题,我似乎无法在其他地方找到答案。有人可以向我解释为什么所有这些都是用外行语言发生的吗?先感谢您。

编辑:

Console.WriteLine(8.001-0.001 == 8); //this return false
Console.WriteLine(8.01-0.01 == 8); //this return true

注意:我正在使用.NET fiddle在线 c# 编译器。

标签: c#castingfloating-pointprecision

解决方案


0.8−0.7的案例

0.8-0.7 == 0.1中,没有任何文字可以在 中完全表示double。The nearest representable values are 0.8000000000000000444089209850062616169452667236328125 for .8, 0.6999999999999999555910790149937383830547332763671875 for .7, and 0.1000000000000000055511151231257827021181583404541015625 for .1. 减去前两个,结果是 0.100000000000000088817841970012523233890533447265625。由于这不等于第三个,因此0.8-0.7 == 0.1评估为假。

在中,和(float)(0.8-0.7) == (float)(0.1)的结果分别转换为。最接近前者的值 0.1000000000000000055511151231257827021181583404541015625 是 0.100000001490116119384765625。最接近后者的值 0.100000000000000088817841970012523233890533447265625 是 0.100000001490116119384765625。由于这些相同,因此评估为 true。0.8-0.70.1floatfloatfloat(float)(0.8-0.7) == (float)(0.1)

在中,和(double)(0.8-0.7) == (double)(0.1)的结果分别转换为。由于它们已经是 ,因此没有效果,结果与 for 相同。0.8-0.70.1doubledouble0.8-0.7 == 0.1

笔记

C# 规范,版本 5.0表示float并且double是 IEEE-754 32 位和 64 位浮点类型。我没有看到它明确说明它们是二进制浮点格式而不是十进制格式,但所描述的特征使这一点显而易见。该规范还指出,通常使用 IEEE-754 算术,具有舍入到最近(可能是舍入到最近的关系到偶数),但以下例外情况除外。

C# 规范允许以比标称类型更高的精度执行浮点运算。第 4.1.6 节说“……浮点运算可能以比运算结果类型更高的精度执行……”这通常会使浮点表达式的分析复杂化,但在实例中它与我们无关,0.8-0.7 == 0.1因为唯一适用的操作是0.7from的减法0.8,并且这些数字在同一个 binade 中(在浮点表示中具有相同的 2 次幂),因此减法的结果是完全可表示的,并且额外的精度不会改变结果。只要源文本0.8,0.70.1to的转换double不使用额外的精度并且强制转换为float产生float没有额外精度的 a,结果将如上所述。(C# 标准在第 6.2.1 节中说,从doubleto的转换会float产生一个float值,尽管它没有明确声明此时不能使用额外的精度。)

其他案例

8-0.7 == 7.3中,对于 ,我们有 8个87.29999999999999982236431605997495353221893310546875对于7.30.6999999999999999555910790149937383830547332763671875 对于0.7,和 7.29999999999999982236431605997495353221893310546875 对于8-0.7,结果是真的。

请注意,C# 规范允许的额外精度可能会影响8-0.7. 对此操作使用额外精度的 AC# 实现可能会在这种情况下产生错误,因为它会得到不同的结果8-0.7

在中,对于、对于、对于和对于18.01-0.7 == 17.31,我们有 18.010000000000001563194018672220408916473388671875 ,所以结果是假的。18.010.69999999999999995559107901499373838305473327636718750.717.30999999999999872102307563181966543197631835937517.3117.3100000000000022737367544323205947875976562518.01-0.7

如果它们都被一个浮点数减去,那么减去 18.01 如何减去 8 差?

18.01 大于 8 并且在其浮点表示中需要更大的 2 次方。同样, 的结果18.01-0.7大于的结果8-0.7。这意味着其有效数字中的位(浮点表示的小数部分,以 2 的幂为比例)表示更大的值,导致浮点运算中的舍入误差通常更大。一般来说,浮点格式有一个固定的跨度——从保留的高位到保留的低位之间有一个固定的距离。当您更改为左侧具有更多位(高位)的数字时,右侧的一些位(低位)会被推出,结果会发生变化。


推荐阅读