【发布时间】:2013-10-02 05:16:07
【问题描述】:
为什么单精度浮点数有 7 位精度(或双精度 15-16 位)?
谁能解释一下我们是如何根据分配给 float(Sign(32) Exponent(30-23), Fraction (22-0)) 的 32 位得出的?
【问题讨论】:
标签: types floating-point precision ieee-754 single-precision
为什么单精度浮点数有 7 位精度(或双精度 15-16 位)?
谁能解释一下我们是如何根据分配给 float(Sign(32) Exponent(30-23), Fraction (22-0)) 的 32 位得出的?
【问题讨论】:
标签: types floating-point precision ieee-754 single-precision
有效数字的 23 个小数位 (22-0) 出现在内存格式中,但总精度实际上是 24 位,因为我们假设有一个前导 1。这相当于 log10(2^24) ≈ 7.225 十进制数字。
双精度浮点数有 52 位小数,加上前导 1 是 53。因此双精度可以容纳 log10(2^53) ≈ 15.955 十进制数字,而不是 16。
注意:前导 1 不是符号位。它实际上是 (-1)^sign * 1.ffffffff * 2^(eeee-constant) 但我们不需要将前导 1 存储在分数中。符号位仍然必须存储
有些数字不能表示为 2 的幂和,例如 1/9:
>>>> double d = 0.111111111111111;
>>>> System.out.println(d + "\n" + d*10);
0.111111111111111
1.1111111111111098
如果财务程序在没有自我纠正的情况下一遍又一遍地进行此计算,最终会出现差异。
>>>> double d = 0.111111111111111;
>>>> double sum = 0;
>>>> for(int i=0; i<1000000000; i++) {sum+=d;}
>>>> System.out.println(sum);
111111108.91914201
总计 10 亿次后,我们损失了超过 2 美元。
【讨论】:
(-1)^sign * 1.ffffffff * 2^(eeee-constant),但我们不需要将前导 1 存储在分数中。符号位仍然必须存储
32 float 有 23 位,所以最小单位是
2^(-23) = 0.00000011920928955078125
其他数字只大于0.00000011920928955078125。小于0.00000011920928955078125也不是不可能。其他数字是0.00000011920928955078125组成
0.00000011920928955078125 * n
所以我们可以很容易地表示0.00000x[1-9]。而float32当然可以有6位精度。不要考虑四舍五入,我们可以计算7位数字如下:
0.00000011920928955078125 * 1 = 0.0000001
0.00000011920928955078125 * 2 = 0.0000002
0.00000011920928955078125 * 3 = 0.0000003
0.00000011920928955078125 * 4 = 0.0000004
0.00000011920928955078125 * 5 = 0.0000005
0.00000011920928955078125 * 6 = 0.0000007
0.00000011920928955078125 * 7 = 0.0000008
0.00000011920928955078125 * 8 = 0.0000009
0.00000011920928955078125 * 9 = 0.000001
它不能表示0.0000006。这是float32具有6~7位精度的结果,我们可以在互联网上到处找到。
【讨论】: