c# - 浮点精度中double和float的区别
问题描述
在阅读了这个问题和这个msdn 博客之后,我尝试了几个例子来测试这个:
Console.WriteLine(0.8-0.7 == 0.1);
是的,预期的输出是False
. 因此,我尝试将两边的表达式转换为double
并float
查看是否可以获得不同的结果:
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# 编译器。
解决方案
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.7
0.1
float
float
float
(float)(0.8-0.7) == (float)(0.1)
在中,和(double)(0.8-0.7) == (double)(0.1)
的结果分别转换为。由于它们已经是 ,因此没有效果,结果与 for 相同。0.8-0.7
0.1
double
double
0.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.7
from的减法0.8
,并且这些数字在同一个 binade 中(在浮点表示中具有相同的 2 次幂),因此减法的结果是完全可表示的,并且额外的精度不会改变结果。只要源文本0.8
,0.7
和0.1
to的转换double
不使用额外的精度并且强制转换为float
产生float
没有额外精度的 a,结果将如上所述。(C# 标准在第 6.2.1 节中说,从double
to的转换会float
产生一个float
值,尽管它没有明确声明此时不能使用额外的精度。)
其他案例
在8-0.7 == 7.3
中,对于 ,我们有 8个8
,7.29999999999999982236431605997495353221893310546875
对于7.3
0.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.01
0.6999999999999999555910790149937383830547332763671875
0.7
17.309999999999998721023075631819665431976318359375
17.31
17.31000000000000227373675443232059478759765625
18.01-0.7
如果它们都被一个浮点数减去,那么减去 18.01 如何减去 8 差?
18.01 大于 8 并且在其浮点表示中需要更大的 2 次方。同样, 的结果18.01-0.7
大于的结果8-0.7
。这意味着其有效数字中的位(浮点表示的小数部分,以 2 的幂为比例)表示更大的值,导致浮点运算中的舍入误差通常更大。一般来说,浮点格式有一个固定的跨度——从保留的高位到保留的低位之间有一个固定的距离。当您更改为左侧具有更多位(高位)的数字时,右侧的一些位(低位)会被推出,结果会发生变化。
推荐阅读
- python - 没有名为 ConfigParser 的模块
- javascript - 如何在 django 中激活显示更多按钮并每页显示 3 个项目
- variables - 暂存云变量
- amazon-web-services - Amazon Textract 未读取单击复选框字段
- azure - Azure Kubernetes - Isito 与 Nginx 控制器?
- php - 使用 PHP 时如何正确格式化 JSON
- c# - .Net核心将SqlConnection注入服务
- c - 为什么在矩阵乘法运算期间,用于存储累加和的变量比直接访问结果单元更快?
- java - Spring. Cannot load driver class: org.hsqldb.jdbc.JDBCDriver
- java - 为什么Java replaceAll() 使用正则表达式需要在前面添加“\\”?