Java 采用 IEEE 754 实现浮点数。
所以我们会看到(见链接部分),在二进制中,float 类型有 24 位精确,在十进制中,float 类型有 log10(2^24)≈7 位精确。
我想问的是,使用 log10(2^24) 这个公式来由二进制精度计算十进制精度的的依据是什么?
我找了一些常见的解释,但还是不能很好地理解。
谢谢。
Why IEEE754 single-precision float has only 7 digit precision?
1
GTim 2021-11-07 11:51:37 +08:00
因为 2^24 = 16777216 ; 9.9999 ^ n < 16777216 < 9.999 ^ (n+1) 可以知道 n = 7
|
2
shintendo 2021-11-07 11:57:09 +08:00
首先,是有效数字 7 位,不是小数点后 7 位,由于小数点位置保存在另一个部分,只看有效数字部分可以当作整数来看,这个整数是用 24 位二进制表示的,所以它的范围是 1 到 2^24 ,对应的十进制数值就是 1 到 log10(2^24)了
|
3
Higurashi OP @GTim #1 感谢回复。是的,的确是这样,但我不明白的是,为什么计算得到的 n 就是十进制下的精确位数?[10506083.html#a4]( https://www.cnblogs.com/HDK2016/p/10506083.html#a4) 中也作了类似说明:
``` 在单精度浮点数中的二进制小数位有 23 个,所能表示 2^23 个数,那么只需要换算成在 10 进制下能够表示相同个数的位数,就可以得到精度了。 10^n = 223 10^n = 8388608 10^6 < 8388608 < 107 所以但精度浮点数的精度为 6 位,同理也可以得到双精度浮点数的精度为 15 位。 ``` 我疑惑的其实是这背后的理由是什么。 |
4
oldshensheep 2021-11-07 12:15:04 +08:00
log10(2^24) = x ≈ 7.225
就是 10^x=16777216 2^24=10^x 换成这样应该明白了吧 |
5
Higurashi OP @shintendo #2 @oldshensheep #4 感谢回复。我稍微懂得了一些。24 位二进制最大为 (1111 1111 1111 1111 1111 1111)2 = (2^24-1)10 ,观察到 100(10^2)<=y<1000(10^3),此时 y 有 [log10y] + 1 = 3 个有效位,类似可以知道 2^24-1 有 [log10(2^24-1)] + 1 个有效位。
但是小于 2^24-1 的 24 位二进制数转换为 10 进制也还是 [log10(2^24-1)] + 1 个有效位吗?比如 (0000 0000 0000 0000 0000 001)2 在十进制中有多少个有效位? |
6
shintendo 2021-11-07 17:59:53 +08:00
@Higurashi
但是小于 2^24-1 的 24 位二进制数转换为 10 进制也还是 [log10(2^24-1)] + 1 个有效位吗? 不一定,可能更少,但不会更多。这个很简单吧,一个自然数数值减小,它的位数只可能不变或减少。 其实“位数”只是一个粗略的描述,你从有效数字的范围而不是位数出发更容易理解精度: 1. 24 位二进制能表示的整数范围是[0 - 2^24] 2. 所以如果一个浮点数的有效数字小于 2^24 ,就能够被精确表示,反之则无法被精确表示 3. 由于 2^24=16777216 是一个 8 位数,所有的 7 位数都小于它,因此有效数字在 7 位以内的数一定能够被精确表示,因此说该格式的精度是 7 位 4. 对于有效数字 8 位的数,一部分(小于 16777216 的)可以精确表示,一部分(大于 16777216 的)不能精确表示;有效数字 9 位以上的数,全部不能精确表示。 |
7
Higurashi OP @shintendo #6
的确,不同的场景有不同的所谓“精度”。我在 https://www.exploringbinary.com/decimal-precision-of-binary-floating-point-numbers/ 中看到了一种定义: “For most of our purposes when we say that a format has n-digit precision we mean that over some range, typically [10^k, 10^(k+1)), where k is an integer, all n-digit numbers can be uniquely identified.” 我觉得暂时只讨论清楚这样一种“精度”比较好,所以现在我的疑惑是,[10^k, 10^(k+1)) 范围内的数字,它能够精确到多少位?是如何得到的?比如,我在源代码中写下一个浮点数,我如何知道从第几位开始程序就不再能够准确地将其表示? 链接指向的文章对此进行了解释,但说实话,我还看不太懂。 |
8
Higurashi OP @shintendo #6
抱歉我没有仔细理解。我想我懂得了你的意思,现在总结一下。 通常所说的精确到多少位(比如 7 ),指的是当我们在源代码中添加一个浮点数字面量时,浮点数超过第 7 位的有效位可能不能够准确表示。 |
9
shintendo 2021-11-10 10:15:55 +08:00
@Higurashi
不只是写在源代码里的,也包括计算产生的数,当我们用 IEEE 754 这种格式去表达一个实数时,前 7 位是可靠的,第 8 位不一定,第 9 位一定不可靠 |
10
shintendo 2021-11-10 10:21:55 +08:00
之所以有一个“不一定”的位,是因为二进制的全 1 对应到 10 进制并不是全 9 。如果你用二进制来看,实际数值相比存储数值,前 24 位可靠(也只有 24 位),24 位以后就丢弃了。
|
11
Higurashi OP @shintendo #9
意思是 23 bit 所保存着的小数转化(数学上的转化,不进行舍入)为十进制数后最多包含 8 位有效数字,且并不是所有拥有 8 位有效位的十进制小数都能够被准确保存? |
12
shintendo 2021-11-10 13:29:22 +08:00
@Higurashi
8 位有效数字的,10000000 - 16777215 可以准确保存,16777216 - 99999999 不能准确保存,见 6 楼 |