How does javascript print 0.1 with such accuracy?

后端 未结 1 1423
粉色の甜心
粉色の甜心 2020-12-11 06:39

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

> 0.3 - 0.2
0.09999999999999998

but I don\'t unders

相关标签:
1条回答
  • 2020-12-11 06:51

    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).

    0 讨论(0)
提交回复
热议问题