为什么0.1+;0.2返回JavaScript中不可预测的浮点结果,而0.2+;0.3不是吗?

为什么0.1+;0.2返回JavaScript中不可预测的浮点结果,而0.2+;0.3不是吗?,javascript,floating-point,precision,Javascript,Floating Point,Precision,我知道这和浮点有关,但这里到底发生了什么 根据@Eric Postpischil的评论,这不是重复的: 这只涉及为什么“噪音”出现在一个加法中。这个 询问为什么“噪波”出现在一个加法中而不出现在 另一个另一个问题没有回答这个问题。因此, 不是复制品。事实上,造成这种差异的原因并不是由于 到浮点运算本身,但由于ECMAScript 2017 7.1.12.1步骤5 这不是javascript本身或任何其他语言的问题,而是两个不同种族之间的交流问题:比如人类和机器,以及两者的思考能力。对我们来说,看

我知道这和浮点有关,但这里到底发生了什么

根据@Eric Postpischil的评论,这不是重复的:

这只涉及为什么“噪音”出现在一个加法中。这个 询问为什么“噪波”出现在一个加法中而不出现在 另一个另一个问题没有回答这个问题。因此, 不是复制品。事实上,造成这种差异的原因并不是由于 到浮点运算本身,但由于ECMAScript 2017 7.1.12.1步骤5


这不是javascript本身或任何其他语言的问题,而是两个不同种族之间的交流问题:比如人类和机器,以及两者的思考能力。对我们来说,看起来很自然的东西(比如一个词:
tree
——当我们说我们在头脑中创建树的抽象表示时)对计算机来说是完全不自然的,机器引用“tree”一词所能做的唯一事情就是以机器容易理解的表示方式存储它(不管你想怎么说,很多年前有人用ASCII表选择了一个二进制代码,但现在它看起来很可靠)因此,此后,机器有一个单词
树的表示,它存储在那里的某个地方,比如说它是
00000001
,但它不知道除此之外的任何东西,对你来说它有一些意义,对机器来说它只是一堆零和一。如果我们说每个单词最多有7位,因为否则com计算机运行缓慢,然后机器将节省最后一位,因此它仍能以某种方式理解单词
tree
。数字也是如此,
0.3
对您来说是很自然的,但当您看到
10101010001010101011010111
时,您会立即将其转换为十进制理解它代表什么,因为在二进制中看到数字是很不自然的。这里有一个要点:转换

因此,对你来说,数学是这样的:

.1+.2=>.3

对于使用二进制系统的机器,如下所示:

数字1/10可以十进制表示为0.1,但二进制表示为0.00011001…..因为根据标准,数字只有53位空间,从第54位开始,数字将四舍五入

x=.1转换为00011001…01并修剪为53位

y=.2转换为00010110…10并修剪为53位

z=x+y=>0001100101…修剪为53位

result=0.3000000000044408929098500626169452667236328125从z=0001100101转换而来…

这就像将欧元兑换成美元一样,有时你会得到半美分,有时你会为一美元的交易多付半美分,因为没有比美分更小的东西了。可能会有,但人们会因为他们的口袋发疯

因此,真正的问题是
为什么0.1转换为二进制和trimmed+0.2转换为二进制和trimmed会在JavaScript中返回不可预测的浮点结果,而0.2转换为二进制和trimmed+0.3转换为二进制和trimmed不会返回不可预测的浮点结果?
答案是:由于数学和计算所赋予的能量,analo为什么
pi+1
给出了奇怪的结果,但是
2+1
没有=>你可能会使用类似
3.1415
的pi表示法,因为你没有足够的数学能力(或者不值得)来得出精确的结果


要了解更多信息,这里做了一个很好的计算:

在JavaScript中将数值转换为字符串时,默认值为.1。这意味着当一个数字显示为“0.1”时,并不意味着它正好是0.1,只是它比任何其他数值都更接近0.1,所以只显示“0.1”告诉您这是唯一的数字值,即0.10000000000000055115123125782702118158340451015625。我们可以用十六进制浮点表示法将其写成0x1.99999999AP-4。(p-4
表示将前面的十六进制数乘以−所以数学家会把它写成1.999999916•2−(四)

以下是在源代码中编写
0.1
0.2
0.3
时产生的值,它们被转换为JavaScript的数字格式:

  • 0.1→ 0x1.9999999999AP-4=0.100000000000000551151231257827021181583404541015625
  • 0.2→ 0x1.9999999999AP-3=0.2000000000011102230246251565040423631668090908203125
  • .3→ 0x1.3333333P-2=0.2999999999988897769753748434595763683319091796875
当我们计算
0.1+0.2
时,我们将0x1.9999999999AP-4和0x1.999999999999ap-3相加。要手动执行此操作,我们可以先将后者的有效位(分数部分)乘以2,然后从其指数中减去一,从而生成0x3.3333334P-4。(您必须以十六进制进行此运算。A16•2=1416,因此最后一个数字为4,1进行进位。然后916•2=1216,进位1为1316。这将产生3位数字和1进位。)现在我们有0x1.9999999999AP-4和0x3.3333333334P-4,我们可以添加它们。这会生成4.ccccccp-4。这是精确的数学结果,但它的数字格式位太多。有效位中只能有53位。4(1002)中有3位尾随的13位中每一位有4位,总共55位。计算机必须删除2位并对结果进行四舍五入。最后一位E16是11102,因此10位必须进行舍入。这些位正好是前一位的½,因此它是向上舍入或向下舍入之间的平局。打破平局的规则
0.1 + 0.2
// => 0.30000000000000004

0.2 + 0.2
// => 0.4

0.3 + 0.2
// => 0.5