格式化浮点值时,JavaScript 如何确定要生成的位数?

IT技术 javascript floating-point precision
2021-01-30 16:23:09

在 JavaScript 中,每个人都知道著名的计算:0.1 + 0.2 = 0.30000000000000004. 但是为什么 JavaScript 打印这个值而不是打印更准确和精确的值0.300000000000000044408920985006

1个回答

将值转换为Number十进制数字时,JavaScript 的默认规则是使用足够的数字来区Number分值。(您可以使用该toPrecision方法请求更多或更少的数字。)

JavaScript 使用 IEEE-754 基本 64 位二进制浮点作为其Number类型。使用 IEEE-754,结果.1 + .2正好是 0.3000000000000000444089209850062616169452667236328125。这源于:

  • 将“.1”转换为Number类型中可表示的最接近的值
  • 将“.2”转换为Number类型中可表示的最接近的值
  • 将上述两个值相加,并将结果四舍五入到Number类型中可表示的最接近的值

格式化该Number值以供显示时,“0.30000000000000004”的有效数字刚好足以唯一区分该值。要看到这一点,请观察相邻值是:

  • 0.299999999999999988897769753748434595763683319091796875,
  • 0.3000000000000000444089209850062616169452667236328125, 和
  • 0.300000000000000099920072216264088638126850128173828125.

如果转换为十进制数字只产生“0.3000000000000000”,这将是更接近0.299999999999999988897769753748434595763683319091796875比0.3000000000000000444089209850062616169452667236328125。因此,需要另一个数字。当我们有那个数字“0.30000000000000004”时,结果比它的任何一个邻居更接近 0.3000000000000000444089209850062616169452667236328125。因此,“0.30000000000000004”是最短的十进制数字(忽略出于美学目的的前导“0”),唯一区分Number原始值是哪个可能的值。

此规则来自 ECMAScript 2017 语言规范第 7.1.12.1 条中的第 5 步,这是将Numberm转换为十进制数字以进行ToString运算的步骤之一

否则,设Ñķ,和s ^是整数,使得ķ ≥1,10 ķ -1小号<10 ķ,为对数的值小号×10 ñ - ķ,并且ķ是尽可能小。

这里的措辞有点不准确。我花了一段时间才弄清楚,通过“ s × 10 n - kNumber数值”,标准的意思是将数学值s × 10 n - k转换为Number类型(通常的四舍五入)。在这个描述中,k是将使用的有效数字的数量,这一步告诉我们最小化k,所以它说使用最小数量的数字,这样我们产生的数字将在转换回Number类型时,产生原始数m

谢谢你的详细回答。在你看来,Js 会使用 toString 方法格式化这个 Number 值来显示,对吗?
2021-03-26 16:23:09
@GuangLin:我相信是这样,但我对 ECMAScript 规范没有经验。我依稀记得我之前翻阅它时看到过类似的东西,但我必须检查一下。
2021-04-04 16:23:09
非常感谢。如果你有新的发现,请再次评论,让更多​​的程序员知道这个问题。
2021-04-09 16:23:09