浮点戏剧性错误(小数部分完全丢失)
Floating point dramatic error (fractional part is completely lost)
quotient = 43156414f / 3;
我在这里得到 quotient
== 14385472 (完全不是真实值应该是:14385471,333...).它完全失去了所有小数部分!
我知道浮点计算不准确(似乎不是我应该知道的全部),但是,正如我告知的那样,错误可能出现在更远的有效数字处。但是这里的红利只有8位数字。为什么会出现如此严重的错误?
可选子问题:我应该牢记哪些规则以预见将来出现此类错误?
请注意:将除法类型从 float 更改为 double 可解决此问题。
float 的精度为 6-9 位。您的价值太大,无法在没有损失的情况下放入浮点数。
double 的精度约为 15-17 位。
作为示例,检查 (int)43156414f
或 (double)43156414f
的值 - 它们都是 43156416
嗯,float
(Single
) 使用 23 位作为尾数
https://en.wikipedia.org/wiki/Single-precision_floating-point_format
因此 float
可以表示最大 2**24 - 1 == 16777215
的整数,即 接近 到 14385471
。
我们的可能性是:
01001011 01011011 10000001 00111111 correponds to 14385471f (let's add 1 bit)
01001011 01011011 10000001 01000000 correponds to 14385472f
所以我们可以看到我们只有 14385471f
和 14385472f
可供选择;在 floate
的情况下,14385471.33333f
没有位置。
一起来看看
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;
现在,43156414f > 2**24 - 1 (16777215)
和 43156414f
不能表示为 float
但
01001100 00100100 10100000 11110000 corresponds to 43156416
所以quotient
的实际值为
43156416 / 3 == 14385472
最后,如果你想要14385471.33
,Single
不够,试试double
:
// 14385471.333333334
double quotient = 43156414d / 3;
quotient = 43156414f / 3;
我在这里得到 quotient
== 14385472 (完全不是真实值应该是:14385471,333...).它完全失去了所有小数部分!
我知道浮点计算不准确(似乎不是我应该知道的全部),但是,正如我告知的那样,错误可能出现在更远的有效数字处。但是这里的红利只有8位数字。为什么会出现如此严重的错误?
可选子问题:我应该牢记哪些规则以预见将来出现此类错误?
请注意:将除法类型从 float 更改为 double 可解决此问题。
float 的精度为 6-9 位。您的价值太大,无法在没有损失的情况下放入浮点数。
double 的精度约为 15-17 位。
作为示例,检查 (int)43156414f
或 (double)43156414f
的值 - 它们都是 43156416
嗯,float
(Single
) 使用 23 位作为尾数
https://en.wikipedia.org/wiki/Single-precision_floating-point_format
因此 float
可以表示最大 2**24 - 1 == 16777215
的整数,即 接近 到 14385471
。
我们的可能性是:
01001011 01011011 10000001 00111111 correponds to 14385471f (let's add 1 bit)
01001011 01011011 10000001 01000000 correponds to 14385472f
所以我们可以看到我们只有 14385471f
和 14385472f
可供选择;在 floate
的情况下,14385471.33333f
没有位置。
一起来看看
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;
现在,43156414f > 2**24 - 1 (16777215)
和 43156414f
不能表示为 float
但
01001100 00100100 10100000 11110000 corresponds to 43156416
所以quotient
的实际值为
43156416 / 3 == 14385472
最后,如果你想要14385471.33
,Single
不够,试试double
:
// 14385471.333333334
double quotient = 43156414d / 3;