浮点戏剧性误差(小数部分完全丢失)

Floating point dramatic error (fractional part is completely lost)

提问人:user1234567 提问时间:7/11/2020 最后编辑:user1234567 更新时间:7/14/2020 访问量:237

问:

quotient = 43156414f / 3;

我在这里得到了 == 14385472(完全不是真正的值:14385471,333......它完全失去了所有部分!quotient

我知道浮点计算不准确(似乎,不是全部,我应该知道),但是,正如我所告知的,错误可能出现在更远的有效数字上。但这里的股息只有 8 位数字。为什么会发生如此戏剧性的错误?

可选子问题:我应该记住哪些规则来预见将来的此类错误?

请注意:将除数类型从浮点数更改为双倍数可以解决此问题。

C# 浮动精度

评论

0赞 Bloodday 7/11/2020
使用decimal类型,它可以保存比float更大的值,并且不会丢失presicion

答:

7赞 Hans Kesting 7/11/2020 #1

float 的精度为 6-9 位。您的价值太大,无法在不损失的情况下放入浮点数。

double 的精度约为 15-17 位。

举例来说,检查 or 的值 - 它们都43156416(int)43156414f(double)43156414f

评论

0赞 user1234567 7/11/2020
出于某种原因,我的脑海中出现了“像 12 位数字一样的东西”。显然,我搞砸了什么。谢谢!
3赞 Dmitry Bychenko 7/11/2020 #2

好吧,() 使用 23 位作为尾数floatSingle

https://en.wikipedia.org/wiki/Single-precision_floating-point_format

所以可以表示接近的整数。 我们拥有的可能性是:float2**24 - 1 == 1677721514385471

 01001011 01011011 10000001 00111111 correponds to 14385471f (let's add 1 bit)
 01001011 01011011 10000001 01000000 correponds to 14385472f

因此,正如我们所看到的,我们只有和可供选择;在. 让我们来看看14385471f14385472f14385471.33333ffloate

 float x = 14385471.3333333333f;

 byte[] data = BitConverter.GetBytes(x);

 Console.Write(" ", string.Join(" ", data
   .Reverse()
   .Select(b => Convert.ToString(b, 2).PadLeft(8, '0'))));

我们将有

 01001011 01011011 10000001 00111111

对应于 .我们还有更多问题14385471f

 quotient = 43156414f / 3;

现在,不能表示为 but43156414f > 2**24 - 1 (16777215)43156414ffloat

 01001100 00100100 10100000 11110000 corresponds to 43156416 

所以实际值是quotient

 43156416 / 3 == 14385472      

最后,如果想要拥有,还不够,试试:14385471.33Singledouble

 // 14385471.333333334
 double quotient = 43156414d / 3;