Skip to content

BigInt与IEEE-754

小数的进制转换

小数的十进制转换为二进制,二进制转换为十进制

  • 十进制转换为二进制
text
20.25 = 20 + 1/4 = 16 + 4 + 1/4 = 10100.01
  • 二进制转换为十进制
text
10100.01 = 1 * 2 ** 4 + 1 * 2 ** 2 + 1 * 2 ** (-2)

IEEE-754

IEEE二进制浮点数算术标准(IEEE 754)是20世纪80年代以来最广泛使用的浮点数运算标准,为许多CPU与浮点运算器所采用。

这个标准定义了:

  • 表示浮点数的格式(包括负零-0)与反常值(denormal number)
  • 一些特殊数值((无穷(Inf)与非数值(NaN))
  • 这些数值的“浮点数运算符”

也指明了四种数值舍入规则和五种例外状况(包括例外发生的时机与处理方式)。

它规定了4种表示浮点数的方式:

  • 单精度(32位)
  • 双精度(64位)
  • 延伸单精度(43位以上,但很少使用)
  • 延伸双精度(79位以上,通常以80位实现)

浮点数表示

一个浮点数的实际值可以这样表示:

Value=sign×exponent×fraction

其中:

  • sign表示符号位
  • exponent表示指数偏移值,也称为阶码

INFO

exponent等于指数的实际值+某个固定的值,IEEE-754规定这个固定值是2n-1-1,其中n为指数域长度

例如:32位单精度的指数域长度为8个比特,那么这个固定值就是28-1-1=127

  • fraction表示分数值,有时也称为尾数。用于存储数值的小数部分

用公式表示如下:

Number=(1)sign(1+fraction)2exponent

用图表示如下:

各部分位数

单精度和双精度的各个部分位数长度如下:

类型符号位指数偏移值尾数
单精度1(最高位)8( [23,31) )23( [0,23) )
双精度1(最高位)11( [52,63) )52( [0,52) )

以单精度为例,举例说明在IEE-754下浮点数的转换

  • 十进制转换为浮点数

    78.125 = 1001110.0012=1.0011100012 * 26

阶码部分:6+127=133=100001012,最终得到的32位浮点数表示为:

0_10000101_001110001000000000000002

WARNING

尾数部分只存储小数部分,IEEE-754规定最高位默认为1,故省略。在转换为十进制时自动加上

  • 浮点数转换为十进制

0_10000101_001110001000000000000002

尾数部分为:1.0011100012

阶数部分为:100001012 = 133 => 133 - 127 = 6

最终转换为十进制表示下的数值为:1.0011100012 * 26 = 1001110.0012 = 78.125

INFO

在相互转换时,需要来回加或减2n-1-1(其中n为指数域长度),这样不是很麻烦么?

对于任意一个浮点数而言,它不仅仅符号位可能为负,而且指数部分也可能为负(例如0.125)。其实IEEE-754指定的这种计算规则,是为了确保指数部分恒为正数。

这样可以简化两个浮点数的比较过程,只需要按位从高到底进行比较即可

浮点表示法

以上介绍的时IEEE-754种最常见的规格化浮点表示法,此外还有非规格化无穷NaN这4种表示法。

以单精度为例:

类型符号数实际指数指数偏移值尾数
00-1270000 0000 0000 0000 0000 0000
-01-1270000 0000 0000 0000 0000 0000
正无穷0128255000 0000 0000 0000 0000 0000
负无穷1128255000 0000 0000 0000 0000 0000
NaN*128255非全0

正数下,最大的非规格化数等于最小的规格化数。如果一个浮点数的指数部分为0,尾数部分不为0,那么这个数应该按照非规格化浮点数来解析

number

在JavaScript中,数字不分为整数类型和浮点型类型,所有的数字都是由浮点型类型

JavaScript 采用 IEEE754 标准定义的 64 位浮点格式表示数字,一个数值可以容纳的最大值是 21024 - 1(指数为 1023,尾数为基于二进制的 0.1111…),可以通过 Number.MAX_VALUE 获得。

超过这个值的数会被替换为特殊的数值常量 Infinity

极值:

  • 最大值(Number.MAX_VALUE)为 ±1.7976931348623157e+308
  • 最小值(Number.MIN_VALUE)为 ±5e-324。

只有在 -253 + 1 到 253 - 1 范围内(闭区间)的整数才能在不丢失精度的情况下被表示(可通过 Number.MIN_SAFE_INTEGERNumber.MAX_SAFE_INTEGER 获得),因为尾数只能容纳 53 位(包括前导 1)。

超出这个范围的值就无法保证比较是正确的,例如:

js
2 ** 53 === 2 ** 53 + 1; // true

如果需要对超出这个范围的值进行运算,可以通过ES6提供的BigInt对象

BigInt

BigInt 是一种内置对象,它提供了一种方法来表示大于 2^53 - 1 的整数。这原本是 Javascript 中可以用 Number 表示的最大数字。BigInt 可以表示任意大整数

不过,它不适合加密,因为它并没有考虑防止时序攻击

INFO

什么是时序攻击

在给定的算法中,如果输入值不同,程序的执行时间也会不同。攻击者可以根据执行时间,不断调整输入值位数上的值来得到正确的输入值

解决方案:

给定一个标志位,即使不同的输入值,也只会在给定时间节点返回。

参考:

【1】讲一讲关于js的number类型

【2】JavaScript Number 对象

【3】IEEE 754

【4】从科学记数法到浮点数标准IEEE 754

【5】Number

【6】BigInt