js 单精度浮点数转10进制_js 数值精度损耗之 IEEE 754 浮点数

IEEE 754 浮点数

浮点型数据是用来表示具有小数点的实数。为什么在C中把实数称为浮点数呢?在C语言中,实数是以指数形式存放在存储单元中的。一个实数表示为指数可以有不止一种形式,如3.14159可以表示为:3.14159×10e0,0.314159×10e1,0.0314159×10e2,31.4159×10e-1,314.159×10e-2等,它们代表同一个值。可以看出:小数点的位置是可以在314159几个数字之间和之前或之后浮动的,只要在小数点位置浮动的同时改变指数的值,就可以保证它的值不会改变。由于小数点位置可以浮动,所以实数的指数形式称为浮点数。

单精度和双精度的存储结构:

浮点数的存储结构分为单精度和双精度。单精度总共4字节32位,双精度总共8字节64位。

以单精度为例,探讨十进制小数转化二进制过程:

十进制小数需要先转化为二进制小数,再进行存储。

小数先转二进制数

格式化为"尾数+阶码"的形式,即 1.M * 2E−127{2^{E-127}}2E−127(M为二进制小数,E为阶码,127为偏移量,E - 偏移量 = 实际的二进制指数)

分别存储"符号"、"阶码"、"尾数" 3个纬度的信息

以 123.456 为例子:

/**

* 十进制转二进制

* 整数部分:不断除2,取余数,直到商为0

* 小数部分:不断乘2,取整数,直到积为0

*

* 计算过程

* 整数

* 123/2 = 61(1);

* 61/2 = 30(1);

* 30/2 = 15(0);

* 15/2 = 7(1);

* 7/2 = 3(1);

* 3/2 = 1(1);

* 1/2 = 0(1);

* 逆向取值,所以整数转为二进制:1111011

*

* 小数

* 0.456*2 = 0.912(0);

* 0.912*2 = 1.824(1);

* 0.824*2 = 1.648(1);

* 0.648*2 = 1.296(1);

*

* 0.296*2 = 0.592(0);

* 0.592*2 = 1.184(1);

* 0.184*2 = 0.368(0);

* 0.368*2 = 0.736(0);

* ... 无限不循环

*

* 正向取值,所以小数转化为二进制:0111 0100 1011 1100 0110 1010 0111 1110 1111 1001 1101 1011

*

* 故该十进制对应的二进制数为:1111011.011101001011110001101010011111101111100111011011

* 转成"尾数+阶码"的格式为:1.111011011101001011110001101010011111101111100111011011 * 2^6,所以阶码E应该为 6 + 127 = 133

* 精度损失之后保留23位:1.11101101110100101111000 * 2^6

*

* 符号为正,故是0

* 阶码为6,而存储阶码时,32位偏移量为127(64位为1023),所以实际应该存 127+6 = 133,转成二进制为 1000 0101

* 尾数直接取二进制小数 11101101110100101111000

* 最后转成单精度的值为 0 10000101 11101101110100101111000

*/

复制代码

以上是十进制转单精度二进制的过程,以下对浮点数进行详细讨论。

浮点数的分类

以双精度为例,阶码位数为 11位,所以阶码E的取值范围 [0, 2047]。

规格化

当阶码不为 0(每一位都为0) 和 2047(每一位都为1) 时,即是规格化的浮点数,表示成二进制小数的格式为 1.M * 2E−1023{2^{E-1023}}2E−1023。

非规格化

当阶码为 0(每一位都为0) 时,为非规格化的浮点数,用于表示0或者非常接近0的数。它的尾数不会像规格化数据那样加1,为了平滑从非规格化数据过渡到规格化数据,它的阶码为 1-1023,故非规格化的格式为 0.M * 2−1022{2^{-1022}}2−1022。

当 M 全为0时,依据符号位分别表示正负0。

无穷大

当阶码为 2047(每一位都为1),所有尾数位为0,代表无穷大,按符号位分为正无穷大和负无穷大。

NaN

当阶码为 2047(每一位都为1),尾数位非全为0,代表 NaN。

以双精度为例探讨值范围

实数范围

规格数

指数范围:阶码范围为 [1, 2046],所以指数范围为 [-1022, 1023]。

小数范围:双精度中,尾数位数52位,所以尾数的十进制范围在 [0, ∑i=1522−i\sum_{i=1}^{52} 2^{-i}∑i=152​2−i],通过等比数列求和可得尾数范围 [0, 1 - 2−52{2^{-52}}2−52]。而由于浮点数存储时忽略了最开始的1,它对应10进制的值也是1,所以小数实际范围应该是 [1, 2 - 2−52{2^{-52}}2−52]。注等比数列求和公式:a1−anq1−q\frac{a_1 - a_nq}{1-q}1−qa1​−an​q​。

所以双精度的最大值即为 小数范围最大值 x 指数范围最大值,故最大值为:

二进制小数 x 21023{2^{1023}}21023 = 十进制小数 x 21023{2^{1023}}21023 = (2 - 2−52{2^{-52}}2−52) x 21023{2^{1023}}21023 ≈\approx≈ 1.797693135 x 10308{10^{308}}10308

即双精度的最小负值:-1.797693135 x 10308{10^{308}}10308,对应 js 中的 -Number.MAX_VALUE;最大正值:1.797693135 x 10308{10^{308}}10308,对应 js 中的 Number.MAX_VALUE。

注:【二进制小数 x 2二进制指数{2^{二进制指数}}2二进制指数】 转十进制的方法: 【二进制小数对应的十进制小数 x 2二进制指数{2^{二进制指数}}2二进制指数】

非规格数

在非规格数中,最小值的表示为 0 00000000000 0...1,对应的十进制数为 2−1022{2^{-1022}}2−1022 x 2−52{2^{-52}}2−52 = 2−1074{2^{-1074}}2−1074 = 5 x 10−324{10^{-324}}10−324,它等于 js 中的 Number.MIN_VALUE。

实数范围总结

结合非规格数和规格数的实数范围,得出总的实数范围 [-1.797693135 x 10308{10^{308}}10308, -5 x 10−324{10^{-324}}10−324] ⋃\bigcup⋃ 0 ⋃\bigcup⋃ [5 x 10−324{10^{-324}}10−324, 1.797693135 x 10308{10^{308}}10308]。

以上范围内的实数存储时可能存在精度损耗问题,以下讨论没有损耗的整数范围。

无损整数范围

双精度存储整数时,并非所有整数都能精确存储,只有在某个范围内的整数才能精确存储,超出范围的整数可能存在精度损耗。整数存储时,先转二进制,再移位,最后把小数点后的数存入尾数部分。如十进制10,转二进制为1010,移位之后变为 1.010 * 23{2^3}23,然后将 010 存入尾数部分。由于双精度的尾数部分只有52位,所以当移位之后的小数部分长度大于52时,就会损失精度。当尾数长度 = 52 时,全部位为1时为最大无损整数,即 1.111...(52位),重新移位回整数再转成的十进制值应该为 253{2^{53}}253 - 1,即 9007199254740991,对应 js 中的 Number.MAX_SAFE_INTEGER。

综上,所以无损整数范围为 [-9007199254740991, 9007199254740991] === [Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]

总结

js 中的数值都是依照 IEEE 754 标准,采用双精度进行存储。所以 js 的数值范围等同于双精度浮点数的范围,即:

实数范围为: [-1.797693135 x 10308{10^{308}}10308, -5 x 10−324{10^{-324}}10−324] ⋃\bigcup⋃ 0 ⋃\bigcup⋃ [5 x 10−324{10^{-324}}10−324, 1.797693135 x 10308{10^{308}}10308]

无损整数范围为:[-9007199254740991, 9007199254740991]

它们的值都存储在 js 的 Number 中,即:

实数范围为:[-Number.MAX_VALUE, -Number.MIN_VALUE] ⋃\bigcup⋃ 0 ⋃\bigcup⋃ [Number.MIN_VALUE, Number.MAX_VALUE]

无损整数范围为:[Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值