当前位置: 首页 > 知识库问答 >
问题:

浮点精度中double和float的差异

周博达
2023-03-14

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

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

是的,预期输出为假。因此,我尝试将表达式的两侧强制转换为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 FIDLE联机c#编译器。

共有1个答案

乔丁雨
2023-03-14

0.8-0.7==0.1中,没有任何文字可以在double中精确表示。对于.8,最接近的可表示值为0.80000000000000440892098500626169452667236328125;对于.7,最接近的可表示值为0.6999999999555910790149938383830547332763671875;对于.1,最接近的可表示值为0.1000000000000000555115123125782702118158340411015625。将前两者相减后,结果为0.1000000000000088817841970012523233890533447265625。由于这不等于第三个值,0.8-0.7==0.1的计算结果为false。

(float)(0.8-0.7)==(float)(0.1)中,将0.8-0.70.1的结果分别转换为float。最接近前者的浮点值0.100000000000000551151231257827021181583404541015625为0.10000001490119384765625。最接近后者的浮点值0.1000000000000088817841970012523233890533447265625为0.10000001490119384765625。由于它们是相同的,(float)(0.8-0.7)==(float)(0.1)的计算结果为true。

(double)(0.8-0.7)==(double)(0.1)中,将0.8-0.70.1的结果分别转换为double。由于它们已经是双倍的,因此没有影响,结果与0.8-0.7==0.1的结果相同。

C规范5.0版指出,浮点和双浮点是IEEE-754 32位和64位浮点类型。我看不出它明确指出它们是二进制浮点格式,而不是十进制格式,但所描述的特性表明了这一点。该规范还规定,通常使用IEEE-754算法,四舍五入到最近(大概是四舍五入到最近的关系到偶数),但以下情况除外。

C#规范允许以比标称类型更高的精度执行浮点运算。第4.1.6条规定“……浮点运算的执行精度可能高于运算的结果类型……”这通常会使浮点表达式的分析复杂化,但在0.8-0.7==0.1的情况下,这与我们无关,因为唯一适用的运算是从0.8中减去0.7,而且这些数字在相同的二进制中(在浮点表示中具有相同的二次幂),因此减法的结果是可以精确表示的,并且额外的精度不会改变结果。只要将源文本0.80.70.1转换为double时不使用额外的精度,并且转换为float时不产生额外精度的float,结果将如上所述。(C#标准在第6.2.1条中指出,从双精度到浮点值的转换会产生一个浮点值,尽管它没有明确说明此时不能使用额外的精度。)

在<代码>8-0.7==7.3<代码>中,我们有8个用于<代码>8<代码>,<代码>7.299999999999822364316059974953221893310546875<代码>7.3<代码>0.699999999999995559107901499937383054732763671875<代码>0.7<代码>7.2999999999999999998223643160599749532218946875.7,因此结果为真。

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

18.01-0.7 == 17.31中,我们18.01000000000000156319401867222040891647338867187518.010.6999999999999999555910790149937383830547332763671875用于0.717.309999999999998721023075631819665431976318359375用于17.31,以及17.31000000000000227373675443232059478759765625用于18.01-0.7,因此结果为false。

如果用浮点数减去8和18.01,那么如何从减去18.01的差中减去8呢?

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

 类似资料:
  • 运行以下代码时,我希望收到这样的输出: 但结果如下: 欢迎任何能指导我正确使用浮点比较和正确使用setprecision的建议。

  • 本文向大家介绍C++中double浮点数精度丢失的深入分析,包括了C++中double浮点数精度丢失的深入分析的使用技巧和注意事项,需要的朋友参考一下 看了一篇关于C/C++浮点数的博文,在Win32下,把int, 指针地址,long等4字节整数赋给一个double后,再用该double数赋给原始类型的数,得到的结果于最初的数值一致,即不存在任何精度丢失。例如下面的结果将总是true: 但是对于l

  • 问题内容: 是否在任何地方都有Java库可以对IEEE 754半精度 数字执行计算或将其与双精度数字进行转换? 这些方法中的任何一种都是合适的: 将数字保持为半精度格式,并使用整数算术和位扭曲(如MicroFloat的单精度和双精度)进行计算 以单精度或双精度执行所有计算,转换成半精度以进行传输(在这种情况下,我需要经过良好测试的转换函数。) 编辑 :转换需要100%准确- 输入文件中 有 很多N

  • 问题内容: 众所周知,即使是十进制格式的小数点后有固定数字的浮点数也无法准确表示。因此,我有以下程序要测试: 输出如下: 我无法从上述结果中回答两个问题,我正在寻求以下方面的帮助: 为什么使用的双重表示形式,并且看起来很精确,而没有。 为什么返回true? 问题答案: 我怀疑在这里不能正常工作。写入0.1时,获取确切值的一种可靠方法是write 。 “为什么0.1f + 0.2f == 0.3f返

  • 众所周知,浮点数,即使是小数点后固定数字的十进制格式,也不能准确表示。所以我有以下程序要测试: 输出如下: 以上结果中有两个问题我无法回答,我正在寻求帮助: 为什么0.1、0.2和0.3的双重表示看起来很精确,而0.1、0.2却不精确。