javascript如何以这样的精度打印0.1? [英] How does javascript print 0.1 with such accuracy?

查看:170
本文介绍了javascript如何以这样的精度打印0.1?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

听说 javascript数字< IEEE 754 浮点数,这就解释了为什么
$ b

 > 0.3  -  0.2 
0.09999999999999998

但我不明白

 > 0.1 
0.1

我认为0.1不能被精确地存储为基2浮点,但它打印出来就像是一直在0.1。是什么赋予了?解释器在打印之前做了一些四舍五入的处理吗?

IEEE 754至少有两个版本并不能帮助我: 1984 edition and 2008年。听起来像后者增加了全面支持十进制算术。似乎并不像我们那样。 JavaScript使用IEEE-754双精度数字(binary64,如2008规范所述;也就是说,像你一样怀疑这是基本的2版本,而不是2008年的基本版本10)。

你得到字符串0.1的原因 0.1 不能完全用binary64表示,那么$ c>对于数值 0.1

TL; DR :字符串不是数字的精确版本,只是足够精确地区分它从其相邻的不完全确切的数字



 该规范定义了将数字转换为字符串的复杂规则,以解决缺少精度。它们在§9.8.1 - ToString应用于数字类型



  1. 如果 m 如果 m ,则返回字符串 NaN 返回字符串0

  2. 如果 m >小于零,则返回字符串 - 和ToString( - m )的字符串连接。
  3. 如果 m 是无穷大,返回String Infinity
  4. 否则,让 n k< em>和< em< em>是整数,使得k≥1,10≤k-1≤s< 10 时,s×10 n-k 的Number值是 m k 可能。请注意, s 的十进制表示中的数字位数, s 不能被10整除,而最低有效位 不一定由这些标准唯一确定。 返回由 s 的十进制表示形式的 k 数字组成的字符串(按照顺序,没有前导零),接着是 n-k 字符'0'的出现
  5. 如果0 < n≤21,返回由 s 的十进制表示形式的最重要的 n 数字组成的字符串,后跟小数点'。' ,然后是 s 的十进制表示的剩余的 k-n 数字。 n≤0,返回由字符'0'组成的字符串,后跟小数点'。',然后返回 - n 字符'0',紧接着是 s 的十进制表示形式的 k 数字。 >否则,如果 k = 1,则返回由 s 的单个数字后跟小写字符'e'组成的字符串,后跟根据 n -1是正值还是负值,使用加号'+'或减号' - '整数abs( n -1)(不含前导零)。
  6. 返回由的十进制表示的最高有效位组成的字符串 ,紧跟着一个小数点'。',接着是 s 的十进制表示的剩余 k ,其次是低然后是符号'+'或减号' - ',然后根据 n em> -1是正数或负数,后面跟着整数abs( n -1)的十进制表示形式(不带前导零)。


然后有以下注释;请点击链接了解详细信息。注3可能最相关:

lockquote

注3

ECMAScript的实现者可能会发现David M.Gay编写的用于浮点数的二进制到十进制转换的论文和代码:

Gay M.正确的二进制十进制和十进制二进制转换。数值分析,手稿90-10。 AT& T贝尔实验室(新泽西州Murray Hill)。 1990年11月30日。可作为
http://cm.bell-labs.com/cm/cs/doc/90/4-10.ps.gz 。关联的代码可以作为
http://cm.bell-labs .com / netlib / fp / dtoa.c.gz
http://cm.bell-labs.com/netlib/fp/g_fmt.c.gz ,也可以在各种netlib镜像站点找到。


对于我来说,4-10.ps.gz文件似乎被破坏了(无法读取第6-8页),但是我在这里找到了PDF:一个href =http://ampl.com/REFS/rounding.pdf =noreferrer> http://ampl.com/REFS/rounding.pdf (不是随意的链接,因为它可能看来,显然 AMPL 是本文工作的主要动机)。

b $ b

I've heard that javascript Numbers are IEEE 754 floating points, which explains why

> 0.3 - 0.2
0.09999999999999998

but I don't understand

> 0.1
0.1

I thought 0.1 couldn't be accurately stored as a base 2 floating point, but it prints right back out, like it's been 0.1 all along. What gives? Is the interpreter doing some rounding before it prints?

It's not helping me that there are at least 2 versions of IEEE 754: 1984 edition and 2008. It sounds like the latter added full support for decimal arithmetic. Doesn't seem like we have that.

解决方案

JavaScript uses IEEE-754 double-precision numbers ("binary64" as the 2008 spec puts it; that is, as you suspected, it's the base 2 version, not the 2008 base 10 version).

The reason you get the string "0.1" for the number value 0.1, even though 0.1 can't be perfectly represented in binary64, is that —

TL;DR: the string isn't an exact version of the number, it's just exact enough to differentiate it from its neighboring not-quite-exact numbers

— the specification defines complex rules for converting numbers to strings in order to address that lack of precision. They're covered in §9.8.1 - ToString Applied to the Number Type:

  1. If m is NaN, return the String "NaN".
  2. If m is +0 or −0, return the String "0".
  3. If m is less than zero, return the String concatenation of the String "-" and ToString(−m).
  4. If m is infinity, return the String "Infinity".
  5. Otherwise, let n, k, and s be integers such that k ≥ 1, 10k−1 ≤ s < 10k, the Number value for s × 10n−k is m, and k is as small as possible. Note that k is the number of digits in the decimal representation of s, that s is not divisible by 10, and that the least significant digit of s is not necessarily uniquely determined by these criteria.
  6. If kn ≤ 21, return the String consisting of the k digits of the decimal representation of s (in order, with no leading zeroes), followed by n−k occurrences of the character ‘0’.
  7. If 0 < n ≤ 21, return the String consisting of the most significant n digits of the decimal representation of s, followed by a decimal point ‘.’, followed by the remaining k−n digits of the decimal representation of s.
  8. If −6 < n ≤ 0, return the String consisting of the character ‘0’, followed by a decimal point ‘.’, followed by −n occurrences of the character ‘0’, followed by the k digits of the decimal representation of s.
  9. Otherwise, if k = 1, return the String consisting of the single digit of s, followed by lowercase character ‘e’, followed by a plus sign ‘+’ or minus sign ‘−’ according to whether n−1 is positive or negative, followed by the decimal representation of the integer abs(n−1) (with no leading zeroes).
  10. Return the String consisting of the most significant digit of the decimal representation of s, followed by a decimal point ‘.’, followed by the remaining k−1 digits of the decimal representation of s, followed by the lowercase character ‘e’, followed by a plus sign ‘+’ or minus sign ‘−’ according to whether n−1 is positive or negative, followed by the decimal representation of the integer abs(n−1) (with no leading zeroes).

Then there are following notes; follow the link for the full details. Note 3 is probably most relevant:

NOTE 3

Implementers of ECMAScript may find useful the paper and code written by David M. Gay for binary-to-decimal conversion of floating-point numbers:

Gay, David M. Correctly Rounded Binary-Decimal and Decimal-Binary Conversions. Numerical Analysis, Manuscript 90-10. AT&T Bell Laboratories (Murray Hill, New Jersey). November 30, 1990. Available as http://cm.bell-labs.com/cm/cs/doc/90/4-10.ps.gz. Associated code available as http://cm.bell-labs.com/netlib/fp/dtoa.c.gz and as http://cm.bell-labs.com/netlib/fp/g_fmt.c.gz and may also be found at the various netlib mirror sites.

For me, the 4-10.ps.gz file seemed to be corrupted (couldn't read pages 6-8), but I found a PDF here: http://ampl.com/REFS/rounding.pdf (not as random a link as it may seem, apparently AMPL was a prime motivation for the work in the paper).

这篇关于javascript如何以这样的精度打印0.1?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆