IEEE,Institute of Electrical and Electronics Engineers
,电气电子工程师学会(美)的缩写。754 标准,是其制定的,关于计算机软硬件中浮点数(小数)的表示和运算的标准,已被各大硬件厂商和编程语言采用,相信学过计算机组成原理、微机系统接口与原理,或任意一门编程语言的同学,对它都既熟悉又陌生,熟悉的是它的名字,陌生的是它的细节,本文将让你和它更熟悉一点。
表示格式
标准规定,浮点数以二进制科学计数法形式存储,具体分 符号 sign
,指数 exponent
和 分数 fraction
三部分。实际值可由如下公式计算:
value = sign x 2^exponent x fraction
其中,分数为二进制小数,小数点前隐含一个 0 或 1
。如果该小数绝对值大于 0 且小于 1,则小数点前为 0,否则为 1。前者称为 非规约形式的浮点数
,后者为 规约形式的浮点数
。
指数采用 移码
存储,使得 整个浮点数能按字典序比较大小
。移码等于实际指数加 偏移量
。记指数位数为 e,对于 规约形式的浮点数
,其偏移量等于 2^(e-1) - 1
,即 [0, 2^e-1] 的 中间值
,非规约形式的浮点数
的偏移量比规约形式 小 1
。
举例来说,32 位浮点数,指数占 8 位,规约形式浮点数的偏移量为 [0, 255] 的中间值 127,非规约形式为 126。64 位浮点数,指数占 11 位,规约形式浮点数的偏移量为 [0, 2047] 的中间值 1023,非规约形式为 1022。
浮点数指数部分的实际取值范围是 [-2^(e-1)+2, 2^(e-1)-1]
,其中 e 为指数所占位数。e 位二进制共能表示 2^e 个数,前述区间少了 2 个,因为左边的 -2^(e-1)+1
被保留用作表示 0
,右边的 2^(e-1)
被保留用作表示 无穷大和 NaN
。
举例来说,32 位浮点数,指数占 8 位,实际取值范围是 [-126, 127],-127 用作表示 0,128 用作表示无穷大和 NaN。64 位浮点数,指数占 11 位,实际取值范围是 [-1022, 1023],-1023 用作表示 0,1024 用作表示无穷大和 NaN。
特殊值
下文中指数均为移码,小数为二进制形式。
- 零。若
指数
为0
,小数部分
也为0
,则该数为±0
。 - 无穷。若
指数
为2^e-1
,小数部分
为0
,则该数为±∞
。 - 非数。若
指数
为2^e-1
,小数部分
非0
,则该数为NaN
。
形式 | 指数 | 小数 |
---|---|---|
零 | 0 | 0 |
非规约形式 | 0 | 大于 0 小于 1 |
规约形式 | 1 到 2^e-2 | 大于等于 1 小于 2 |
无穷 | 2^e-1 | 0 |
NaN | 2^e-1 | 非 0 |
可以看到除了 NaN,从上至下,数值的 绝对值
和对应 指数
都是越来越大的。下面以 32 位单精度浮点数 符号位( 1 位)+ 指数域( 8 位)+ 尾数域( 23 位)
为例,直观介绍其在计算机中的存储。下表中,最大最小均指 绝对值
,符号位的 *
表示 可正可负
,正为 0,负为 1。
类别 | 符号位 | 实际指数 | 偏移指数 | 指数域 | 尾数域 | 数值 |
---|---|---|---|---|---|---|
1 | * | 0 | 127 | 低 7 位为 1 | 全 0 | ±1.0 |
零 | * | -127(保留) | 0 | 全 0 | 全 0 | ±0.0 |
最小非规约数 | * | -126 | 0(偏 126) | 全 0 | 最低位为 1 | ±2^(-126)*2^(-23) |
最大非规约数 | * | -126 | 0(偏 126) | 全 0 | 全 1 | ±2^(-126)*(1-2^(-23)) |
最小规约数 | * | -126 | 1 | 最低位为 1 | 全 0 | ±2^(-126) |
最大规约数 | * | 127 | 254 | 高 7 位为 1 | 全 1 | ±2^127*(2-2^(-23)) |
无穷 | * | 128(保留) | 255 | 全 1 | 全 0 | ±∞ |
NaN | * | 128(保留) | 255 | 全 1 | 非全 0 | 非数 |
着重关注以下 4 点:
- 实际指数的 -127 和 128 保留,分别表示 0 和 ∞/NaN。
- 规约数指数偏移量为 127,非规约减 1。
- 最大非规约数尾数域 + 最小非规约数尾数域 = 1
- 最大规约数尾数域 + 最小非规约数尾数域 = 2
关于 3,4 两点,作二进制加法即可理解:
第 3 点
0. 111 1111 1111 1111 1111 1111 1111 1111 (最大非规约数尾数域)
+ 0. 000 0000 0000 0000 0000 0000 0000 0001 (最小非规约数尾数域)
-------------------------------------------
= 1. 000 0000 0000 0000 0000 0000 0000 0000 (小数点前为隐含值)
第 4 点
1. 111 1111 1111 1111 1111 1111 1111 1111 (最大规约数尾数域)
+ 0. 000 0000 0000 0000 0000 0000 0000 0001 (最小非规约数尾数域)
-------------------------------------------
= 2. 000 0000 0000 0000 0000 0000 0000 0000 (小数点前为隐含值)
64 位双精度浮点数 符号位( 1 位)+ 指数域( 11 位)+ 尾数域( 52 位)
相应值如下:
类别 | 符号位 | 实际指数 | 偏移指数 | 指数域 | 尾数域 | 数值 |
---|---|---|---|---|---|---|
1 | * | 0 | 1023 | 低 10 位为 1 | 全 0 | ±1.0 |
零 | * | -1023(保留) | 0 | 全 0 | 全 0 | ±0.0 |
最小非规约数 | * | -1022 | 0(偏 1022) | 全 0 | 最低位为 1 | ±2^(-1022)*2^(-52) |
最大非规约数 | * | -1022 | 0(偏 1022) | 全 0 | 全 1 | ±2^(-1022)*(1-2^(-52)) |
最小规约数 | * | -1022 | 1 | 最低位为 1 | 全 0 | ±2^(-1022) |
最大规约数 | * | 1023 | 2046 | 高 10 位为 1 | 全 1 | ±2^1023*(2-2^(-52)) |
无穷 | * | 1024(保留) | 2047 | 全 1 | 全 0 | ±∞ |
NaN | * | 1024(保留) | 2047 | 全 1 | 非全 0 | 非数 |
同理有以下 4 点:
- 实际指数的 -1023 和 1024 保留,分别表示 0 和 ∞/NaN。
- 规约数指数偏移量为 1023,非规约减 1022。
- 最大非规约数尾数域 + 最小非规约数尾数域 = 1
- 最大规约数尾数域 + 最小非规约数尾数域 = 2
比较大小
正数一定大于负数,无穷大于所有数,非数不能比较大小;除此之外,则可按指数域和尾数域的字典顺序比较。
舍入规则
很多十进制小数 转为
二进制会 超出尾数域位数
甚至 无限循环
,上述情况在 运算过程中
也有可能发生,这时就需要丢弃部分位,以满足浮点数存储要求,这些原因都导致浮点数不能精确表示所有实数。IEEE 754 规定了以下 4 种舍入规则:
- 舍入到最接近:将结果舍入到最接近且可以表示的值,若存在两个一样接近的值,取偶数(二进制以 0 结尾)。
- 向正无穷方向舍入。
- 向负无穷方向舍入。
- 向 0 舍入。
其中第一种是默认规则,可通过配置指定其他几种。下面以十进制为例,说明以上舍入方法。
round(0.5)=0 // 舍入到最近,0.5 到 0 和 1 距离相等,取偶数 0
ceil(1.324)=2 // 向正无穷舍入
floor(1.324)=1 // 向负无穷舍入
(int)1.324=1 // 向 0 舍入
精度损失
由于浮点数 位数有限
,不可能精确表示所有实数,浮点运算必然存在精度损失。
十进制转二进制
十进制小数转二进制分两部分,整数和小数。整数采用 除二取余
,小数采用 乘二取整法
。举例来说,十进制 7.1
转为 32 位单精度二进制浮点数
的过程如下:先将整数 7
转为二进制 111
,再将小数 0.1
转为二进制,以下是 乘二取整
过程。
0.1 x 2 = 0.2 取 0
0.2 x 2 = 0.4 取 0
0.4 x 2 = 0.8 取 0
0.8 x 2 = 1.6 取 1
0.6 x 2 = 1.2 取 1,下面将是 0011 无限循环
0.2 x 2 = 0.4 取 0
0.4 x 2 = 0.8 取 0
0.8 x 2 = 1.6 取 1
0.6 x 2 = 1.2 取 1
...
可见 0.1
这个十进值小数转为二进制是无限位的,而单精度总共就 32 位,所以只能取其近似值。32 位浮点数尾数是 23 位,因此先采用 就近舍入
取 23 位 000 1100 1100 1100 1100 1101
,现在整个浮点数是 111.000 1100 1100 1100 1100 1101
。然而还要保证小数点前只为 0/1
,所以要把小数点左移 2 位,这样尾数右边就要再丢掉 2 位,采用 就近舍入
最终变为 2^2 * 1.110 0011 0011 0011 0011
,按照标准格式表示,符号位为 0,指数域存储移码 (2+127) 的二进制 1000 0001
,尾数域 110 0011 0011 0011 0011
,即
0 1000 0001 110 0011 0011 0011
s | e | | f |
从上面乘二取整的过程可以看出,0.2, 0.4, 0.6, 0.8
的二进制都是无限位。又因为
0.3 x 2 = 0.6
0.7 x 2 = 1.4
0.9 x 2 = 1.8
所以 0.3, 0.7, 0.9
的二进制也是无限循环的,总结下来,0.1, 0.2, ... , 0.9
这 9 个小数的二进制,只有 0.5
不是无限循环,其他 8 个都无法精确表示。
二进制转十进制
观察以下二进制小数转十进制:
0.1 = 2^-1 => 0.5
0.01 = 2^-2 => 0.25
0.001 = 2^-3 => 0.125
0.0001 = 2^-4 => 0.0625
0.00001 = 2^-5 => 0.03125
0.000001 = 2^-6 => 0.015625
0.0000001 = 2^-7 => 0.0078125
0.00000001 = 2^-8 => 0.00390625
...
由于结果都是 0.x5
形式,而从上至下每次都要除以一个 2
将其变为 0.x25
,即末尾会增加一位。又因为前缀 0.x
除以 2
的位数只增不减(任意小数除以 2 位数不会减少),所以从上至下,结果位数总是增加的。
因此上述各个等式任意相加 除了第一个等式,允许其他等式自身相加
,都无法消掉结尾的 5
,结果总是 0.x5
形式,即有结论 0.x1 = 2^k = 0.y5
,其中 x
可以是任意多个 0/1
,y
可以是任意多个 0-9
。
事实上,上述等式的任意相加,等价于各个二进制位取 0/1
,其所有结果组成的集合就是所有二进制浮点数。反过来说,一个十进制小数如果不以 5 结尾,则不能精确转为二进制浮点数
。
我们知道,m 位十进制数有 10^m 个(每一位有 10 种可能性)。同样地,m 位二进制数有 2^m 个。所以,m 位十进制数能精确用 m 位二进制浮点数表示的比例为 (2/10)^m,即 0.2^m
。对于 32 和 64 位浮点数,其有效二进制位分别为 24 和 53 位,该比例分别为 1.6777216 x 10^(-17)
和 0.9007199247400992 x 10^(-37)
。可以看到 十进制整数越大越不可能转为精确的二进制浮点数
。
运算过程
二进制浮点数的加减运算分 对阶、尾数求和、规格化、舍入和溢出判断
5 步。下面以常考面试题举例,说明上述过程。
问题一:为何以下 JavaScript 代码输出 false?
console.log(0.1 + 0.2 == 0.3);
解析:JS 中的数字都是 IEEE 754 64 位双精度浮点数,进行十进制运算大体分三步:
- 十进制转二进制浮点数
- 二进制数运算
- 二进制结果转十进制
首先完成 进制转换
。
尾数
0.1 => 0.0 0011 0011 0011 0011 0011 0011 0011 0011 .... 循环
0.2 => 0.0 0110 0110 0110 0110 0110 0110 0110 0110 .... 循环
规格化
0.1 => 2^(-4) x 1.1001 1001 1001 1001 1001 1001 1001 .... 循环
0.2 => 2^(-3) x 1.1001 1001 1001 1001 1001 1001 1001 .... 循环
转 64 位浮点数标准格式,尾数就近舍入到 52 位,此处发生精度损失
0.1 => 0,011 1111 1011,1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001(1)
0.1 => 0,011 1111 1011,1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1010(取最近偶数)
0.2 => 0,011 1111 1100,1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1010
接下来进行二进制运算,由于阶数不同,先 对阶
,小阶向大阶看齐
,小阶尾数右移 阶差
位。之所以不左移是因为左边为高位,丢掉损失很大。
0.1 尾数右移 1 位,左边移入隐含的 1,右边移出一个 0,再次产生误差
0.1 => 0,011 1111 1100,1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1101(0)
0.1 => 0,011 1111 1100,1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1101(取最近)
0.2 => 0,011 1111 1100,1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1010
接下来进行 尾数求和
。
0.1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1101
+ 1.1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1010
--------------------------------------------------------------------
10.0110 0110 0110 0110 0110 0110 0110 0110 0110 0110 0110 0110 0111
将尾数 规格化
,指数加 1,尾数右移 1 位,就近 舍入
,再次产生误差。
1.0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011(1) x 2
1.0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0100 x 2 (取最近偶数)
转为标准格式。
0.1 + 0.2 = 0,011 1111 1101,0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0100
0.3 = 0,011 1111 1101,0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011
可以看出两者相差 2^(-52-2)
,并非完全相等。
问题二:写出以下 JavaScript 代码的运行结果
var one = 0.1, two = 0.2, six = 0.6, eight = 0.8;
[two-one == one, eight-six == two];
答案:[true, false]
解析:
前半部分转 IEEE 754
0.1 => 0,011 1111 1011,1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1010
0.2 => 0,011 1111 1100,1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1010
对阶
0.1 => 0,011 1111 1100,1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1101
0.2 => 0,011 1111 1100,1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1010
尾数求和
0.2 => 1.1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1010
0.1 => - 0.1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1101
---------------------------------------------------------------------------
0.1 => 0.1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1101
结果和 0.1 完成相同,因此是 true
后半部分转 IEEE 754
0.6 x 2 = 1.2
0.2 x 2 = 0.4
0.4 x 2 = 0.8
0.8 x 2 = 1.6
0.6 x 2 = 1.2
0.2 x 2 = 0.4
0.4 x 2 = 0.8
...
尾数二进制
0.6 => 0.1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001(1)
0.8 => 0.1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100(1)
尾数取 52 位,就近舍入
0.6 => 0.1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1010
0.8 => 0.1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1101
无需对阶,尾数求和
0.8 => 0.1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1101
0.6 => - 0.1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1010
---------------------------------------------------------------------------
0.0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011
=> 1.1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1000
0.2 => 1.1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1010
结果和 0.2 最后两位不同,因此是 false
问题三:解释以下 JavaScript 中 Number 对象的几个静态属性
Number.EPSILON => 1.0 与距离其最近的可表示的浮点数的差值 => 2^(-52),IEEE 754 格式如下
0,000 0000 0000,0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0001
Number.MAX_VALUE => 可以表示的最大有限数 => 2^1023 x [2-2^(-52)],IEEE 754 格式如下
0,111 1111 1110,1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111
Number.MIN_VALUE => 可以表示的最接近 0 的正数 => 2^(-1022)*2^(-52),IEEE 754 格式如下
0,000 0000 0000,0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0001
Number.MAX_SAFE_INTEGER => 可以精确表示和比较的最大整数 => 2^52 x [2-2^(-52)],IEEE 754 格式如下
0,100 0011 0011,1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111,实际值如下
2^52 x 1.1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111
+ 2^52 x 0.0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0001
-----------------------------------------------------------------
2^53 x 1.0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
+ 2^53 x 0.0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0001
-----------------------------------------------------------------
2^53 x 1.0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0001 => 2^53 x 1 + 2^53 x 2^(-52) => 2^53 + 2
也就是说,虽然最低位只加 1,也就是 2^(-52),但系数是 2^53,乘起来就是 2,从十进制角度就是每次至少加 2
Number.MIN_SAFE_INTEGER => 可以精确表示和比较的最小整数 => -2^52 x [2-2^(-52)],IEEE 754 格式如下
1,100 0011 0011,1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111,实际值如下
-2^52 x 1.1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111
-2^52 x 0.0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0001
---------------------------------------------------------------
-2^53 x 1.0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
-2^53 x 0.0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0001
---------------------------------------------------------------
-2^53 x 1.0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0001 => -2^53 x 1 - 2^53 x 2^(-52) => -2^53 - 2
也就是说,虽然最低位只减 1,也就是 2^(-52),但系数是 -2^53,乘起来就是 -2,从十进制角度就是每次至少减 2
问题四:写出以下 Java 代码的运行结果
public static void main(String[] args) throws Exception {
System.out.println(Math.min(Integer.MIN_VALUE, 0));
System.out.println(Math.min(Float.MIN_VALUE, 0.0f));
try {
int i = 1 / 0;
System.out.println(i);
} catch (Exception e) {
System.out.println("exception 1 / 0");
}
try {
float f1 = 1.0f / 0.0f;
System.out.println(f1);
System.out.println(f1 == f1);
} catch (Exception e) {
System.out.println("exception 1.0f / 0.0f");
}
try {
float f2 = 0.0f / 0.0f;
System.out.println(f2);
System.out.println(f2 == f2);
} catch (Exception e) {
System.out.println("exception 0.0f / 0.0f");
}
}
答案
结果
-2147483648
0.0
exception 1 / 0
Infinity
true
NaN
false
原因
1. Integer 是 int 的包装类,底层仍为 int。int 占 4 字节 32 位,因此取值范围 [-2^31, 2^31-1],2^31=2147483648
2. 整数不能除以 0
3. IEEE 754 有限值除以 0 结果为无穷大
4. IEEE 754 规定无穷等于自身
5. IEEE 754 规定一个数无法确定时,它是 NaN
6. IEEE 754 规定 NaN 与任何数比较都是 false(除了 !=)
问题五:写出以下 C++ 代码的运行结果
float f_v1 = 20;
float f_v2 = 20.3;
float f_v3 = 20.5;
double d_v1 = 20;
double d_v2 = 20.3;
double d_v3 = 20.5;
cout << ((f_v1 == d_v1)?"true":"false") << endl;
cout << ((f_v2 == d_v2)?"true":"false") << endl;
cout << ((f_v3 == d_v3)?"true":"false") << endl;
答案
结果
true
false
true
原因
20 能精确转为二进制,且不超出 float 范围 => 1 0100。上文说过,0.5 能精确转为二进制,且不超出 float 范围 => 0.1,剩下的 0.1-0.4, 0.6-0.9 都不行
0.3 x 2 = 0.6
0.6 x 2 = 1.2
0.2 x 2 = 0.4
0.4 x 2 = 0.8
0.8 x 2 = 1.6
0.6 x 2 = 1.2
...
f_v1 => 20.0 => 1 0100.0 => 1.010 0000 0000 0000 0000 0000
f_v2 => 20.3 => 1 0100.0100 1100 1100 1100 110(0) => 1.010 0010 0010 0010 0010 0010
f_v3 => 20.5 => 1 0100.1 => 1.010 0100 0000 0000 0000 0000
d_v1 => 20.0 => 1 0100.0 => 1.010 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0
d_v2 => 20.3 => 1 0100.0100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100(1) => 1.010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 1
d_v3 => 20.5 => 1 0100.1 => 1.010 0100 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0
最终比较,要把 float 转 double,所以
f_v1 => double,直接补 0,和 d_v1 相等
f_v2 => double,直接补 0,和 d_v2 不等
f_v3 => double,直接补 0,和 d_v3 相等
总结
由于各大编程语言都用 IEEE 754 标准实现浮点数,所以它们的结果大多数情况下都是不准确的,不能按照十进制运算理解,特别是比较大小时。产生误差的具体细节为:
- 十进制转二进制可能超出尾数位数,甚至无限循环,此时必然产生舍入误差。
- 对阶时,小阶尾数右移可能产生舍入误差。
- 规格化时,尾数如需右移同样可能产生舍入误差。
- 单精度表示整数时,最大精度为 2^24 - 1。
- 双精度表示整数时,最大精度为 2^53 - 1。
高精度计算需借助相应语言采用其他方法实现的类库,如 Java 的 BigDecimal
,JavaScript 的 mathjs
等。
参考资料
- IEEE 754 Calculator
- IEEE-754 Analysis
- IEEE-754 Floating-Point Conversion
- Why is 0.1 + 0.2 Not Equal to 0.3 in Most Programming Languages?
- Is floating point math broken?
- Javascript – MAX_INT: Number Limits
- What is JavaScript's highest integer value that a number can go to without losing precision?
- Adding to Number.MAX_VALUE
- 浮点数的运算步骤
- 为什么在 js 中 Number.MAX_VALUE + 1 不是 Infinity
- js 中 0.1 + 0.2 为什么不等于 0.3
如有问题请在下方留言,文章转载请注明出处,详细交流请加下方群组!请大佬不要屏蔽文中广告,因为它将帮我分担服务器开支,如果能帮忙点击我将万分感谢。
你好,32 位单精度浮点数表格中的最小规约数的数值,我算到了正负2^(-125)。你那应该是把1当十进制了。如果我没理解错的话。方便的话,帮我确认下,我想知道IEEE754 float能表示的最小正整数是多少?
绝对值最小规约数是正负 2^(-126)。并且你最后问的有问题,最小正整数当然是 1