-2

I came across some code today:

console.log(Math.ceil(3.000000000000001))
--> 4
console.log(Math.ceil(3.0000000000000001))
--> 3

What happened in the JS interpreter? What rules is it following such that the 1 gets "trimmed" in the second Math.ceil?

What I don't want is a bunch of links to floating point arithmetic... but what specifically is interpreted by JS.

Andrew Kim
  • 3,145
  • 4
  • 22
  • 42
  • 1
    have a look at [floats](https://en.wikipedia.org/wiki/Floating-point_arithmetic). this happens *before* `Math.ceil` so `3.0000000000000001 === 3` is `true`! – Lux Apr 30 '18 at 15:27
  • [Here's another great article](http://2ality.com/2012/04/number-encoding.html) about JavaScript's specific implementation of floating point numbers. – John Ellmore Apr 30 '18 at 15:29
  • Is it because "the base for the scaling is normally two, ten, or sixteen" and there's 16 digits past the decimal? – Andrew Kim Apr 30 '18 at 15:30
  • I don't believe so. This question is about how floats get interpreted. – Andrew Kim Apr 30 '18 at 15:32
  • 2
    I think your question might have been better understood/received if you hadn't used `Math.ceil` which shifts the focus towards [Is floating point math broken?](https://stackoverflow.com/q/588004/11683). `console.log(3.0000000000000001)` and explicitly mentioning parsing of numeric literals would probably be better. – GSerg Apr 30 '18 at 15:41
  • The second number has more digits than Javascript's floating point precision, so it's read as exactly `3.0`. – Barmar Apr 30 '18 at 15:44
  • 1
    I don't think he should give any such examples at all if his interest lies in parsing implementation details - the described behavior is obvious for float64 if he "doesn't want [...] links to floating point arithmetic". However, i don't think he actually wants parsing implementation details - just my glass ball speaking. – ASDFGerte Apr 30 '18 at 15:44
  • Anyways, since it is apparently relevant to the discussion, here: [sec-static-semantics-mv](https://tc39.github.io/ecma262/#sec-static-semantics-mv) – ASDFGerte Apr 30 '18 at 15:59

1 Answers1

3

Javascript floating point numbers have a 51-bit mantissa, which allows for 16 decimal digits of precision. 3.000000000000001 has 16 digits, so the fraction can be included in the floating point value, and then Math.ceil() rounds it up to 4. 3.0000000000000001 has 17 digits, so the fraction doesn't fit, and it gets rounded to 3.0 when reading it, and therefore Math.ceil() returns 3.0.

Barmar
  • 741,623
  • 53
  • 500
  • 612