Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does javascript print 0.1 with such accuracy?

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.

like image 828
hurrymaplelad Avatar asked Feb 13 '15 07:02

hurrymaplelad


1 Answers

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

like image 106
T.J. Crowder Avatar answered Oct 17 '22 20:10

T.J. Crowder