JavaScript浮点数混淆

Mik*_*eNQ 2 javascript rounding data-conversion

我遇到了一些混乱的手术。

var a = 0.1;
var b = 0.2;
var c = 0.3;

console.log(a); // 0.1
console.log(b); // 0.2
console.log(c); // 0.3
Run Code Online (Sandbox Code Playgroud)

但,

consolo.log(a+b+c) // 0.6000000000000001.
Run Code Online (Sandbox Code Playgroud)

console.log(a+(b+c)) // 0.6
Run Code Online (Sandbox Code Playgroud)

我知道Javascript使用二进制浮点数,因此无法准确表示0.1、0.2、0.3,但是(b + c)的括号是什么?这里有什么转换或四舍五入吗?

非常感谢,

Shu*_*ing 5

如何定义JavaScript编号

JavaScript数字在IEEE754中表示为双精度二进制浮点(binary64),以科学计数法表示,并以2为基数。一个数字有64位,它们分为3部分(从高到低):

  • 第一位用于符号:0-正;1-负数
  • 接下来的11位是指数部分
  • 后52位是尾数/小数

在此处输入图片说明

因此,浮点数计算如下: (-1) ^ sign * (2 ^ exponent) * significand

注意:由于科学计数法的指数部分可能为正也可能为负,因此应通过从11位指数值中减去指数偏差(中间值1023)来计算binary64数字的实际指数值。

该标准还将有效值定义为介于0 [1, 2).和1 之间。由于有效部分的第一个数字始终为1,因此在上图中暗含但未显示。因此,基本上有效部分实际上具有53位精度,而上图中的红色部分只是尾数或小数部分。

二进制64格式的0.1、0.2和0.3

根据该标准,不难找到binary64格式的0.1、0.2和0.3(您可以手动或通过此工具http://bartaz.github.io/ieee754-visualization/进行计算):

0.1

0 01111111011 1001100110011001100110011001100110011001100110011010
Run Code Online (Sandbox Code Playgroud)

用科学的符号来说

1.1001100110011001100110011001100110011001100110011010 * 2e-4
Run Code Online (Sandbox Code Playgroud)

注意:有效数字部分为二进制格式,以下数字为相同格式

0.2

0  01111111100 1001100110011001100110011001100110011001100110011010
Run Code Online (Sandbox Code Playgroud)

用科学的符号来说

1.1001100110011001100110011001100110011001100110011010 * 2e-3
Run Code Online (Sandbox Code Playgroud)

0.3

0 01111111101 0011001100110011001100110011001100110011001100110011
Run Code Online (Sandbox Code Playgroud)

用科学的符号来说

1.0011001100110011001100110011001100110011001100110011 * 2e-2
Run Code Online (Sandbox Code Playgroud)

步骤相加2个binary64数字

第1步 -对齐指数

  • 移位指数较小的数字的有效位数
  • 右移有效位数
  • 对于每个有效位数移位,将指数增加1,直到两个指数相同
  • 转移后,有效位数应四舍五入。

第2步 -将有效位数相加

  • 如果相加的有效位数不满足[1,2)要求,则将其移至该范围并更改指数

  • 转移后,有效位数应四舍五入。

0.1 + 0.2 + 0.3 == 0.6000000000000001

如上所述,0.1具有指数-40.2具有指数-3,因此需要首先进行指数对齐:

转变0.1

1.1001100110011001100110011001100110011001100110011010 * 2e-4
Run Code Online (Sandbox Code Playgroud)

0.1100110011001100110011001100110011001100110011001101 * 2e-3
Run Code Online (Sandbox Code Playgroud)

然后添加有效位数

0.1100110011001100110011001100110011001100110011001101
Run Code Online (Sandbox Code Playgroud)

1.1001100110011001100110011001100110011001100110011010
Run Code Online (Sandbox Code Playgroud)

我们得到了重要的价值:

10.0110011001100110011001100110011001100110011001100111
Run Code Online (Sandbox Code Playgroud)

但它不在范围内,[1,2)因此需要将其(向上舍入)右移至:

1.0011001100110011001100110011001100110011001100110100 (* 2e-2)
Run Code Online (Sandbox Code Playgroud)

然后将其添加到

0.3 (1.0011001100110011001100110011001100110011001100110011 * 2e-2) 
Run Code Online (Sandbox Code Playgroud)

我们得到:

10.0110011001100110011001100110011001100110011001100111 * 2e-2
Run Code Online (Sandbox Code Playgroud)

同样,我们需要平移并四舍五入,最后得到值:

1.0011001100110011001100110011001100110011001100110100 * 2e-1
Run Code Online (Sandbox Code Playgroud)

恰好是0.6000000000000001(十进制)的值

使用相同的工作流程,您可以计算出0.1 +(0.2 + 0.3)

工具类

该网页http://bartaz.github.io/ieee754-visualization/可以帮助您快速将十进制数转换为binary64格式,您可以使用它来验证计算步骤。

如果要处理单个精度二进制浮点数,请参考此工具:http : //www.h-schmidt.net/FloatConverter/IEEE754.html