4 ms·
Math in JavaScript: Broken Irrational Numbers
- weinzierl 10y agoYou don't need to summon irrational numbers to get wrong results. For example: 0.3-(3*0.1) is non-zero, no irrational numbers involved. The reason for this is that 1/3 cannot be precisely represented in decimal but (maybe somewhat surprisingly) it can be in binary, hence the correct result for 1/3 + 1/3 + 1/3 = 1. On the other hand 1/10 or 0.1 has no precise representation in binary and is round. The rounding adds up and you get wrong results. This also has nothing to do with Javascript but is a consequence of the way numbers are represented in a computer. Most programming languages deal with numbers roughly the same way and will be affected by this types of problems. Some try to hide their shady slopes though. Microsoft Excel has some heuristics that fudges the results for simple formulas, so you get different result depending on the heuristic. For a more detailed explanation see the classic " What Every Programmer Should Know About Floating-Point Arithmetic" [1] [1] http://www.phys.uconn.edu/~rozman/Courses/P2200_14F/downloads/floating-point-guide-2014-11-03.pdf http://www.phys.uconn.edu/~rozman/Courses/P2200_14F/download...
- tzs 10y ago> The reason for this is that 1/3 cannot be precisely represented in decimal but (maybe somewhat surprisingly) it can be in binary, hence the correct result for 1/3 + 1/3 + 1/3 = 1. 1/3 cannot be precisely represented in (finite) binary. Its representation is 0.0̅1̅.
- weinzierl 10y agoThanks, you are right, see my comment to dragonwriter also.
- deleted 10y ago[deleted]
- tzs 10y ago(This was meant to be appended as an edit to the above, but between the time I started typing it into the update text area and the time I hit the "update" button the comment aged enough to not allow updates, so I'll add it as a reply) In general, a necessary (but not sufficient) condition for the representation of n/m to be precisely represented in base b is that there exists some integer r in [1, m-1] such that rb = 0 mod m. If you work out the representation of n/m using the classic division algorithm, the algorithm terminates iff you hit such an r after one of the subtraction steps. The step on which you hit that r will have produced the next to less digit of the result, and then the algorithm will product one more digit and terminate. When m is a prime (such as m = 3), then (r, m) = 1, and so rb = 0 mod m is only possible if b = 0 mod m. If b = 0 mod m then all r are suitable, and n/m has at most one digit after the radix point.
- dragonwriter 10y ago> The reason for this is that 1/3 cannot be precisely represented in decimal but (maybe somewhat surprisingly) it can be in binary Wait, you've discovered a way to express 1/3 as a sum of integer multiples of integral powers of 2? > This also has nothing to do with Javascript but is a consequence of the way numbers are represented in a computer. Well, it has to do with the use of binary floating point, which is the only kind of number in JavaScript, and the default non-integer type in many (but not all) other languages. OTOH, there are (though, given the historical relationship between CS and math, fewer than you'd think) languages that get basic arithmetic right, like Scheme.
- weinzierl 10y agoYou are right dragonwriter and I am wrong (somewhat surprisingly). No, seriously, I'm sorry, I should think before I post. >Well, it has to do with the use of binary floating point, Binary floating point but fixed point also. >which is the only kind of number in JavaScript, and the default non-integer type in many (but not all) other languages. OTOH, there are (though, given the historical relationship between CS and math, fewer than you'd think) languages that get basic arithmetic right, like Scheme. I was thinking of Python Rationals and Mathematica but the Numerical Tower in Scheme seems even more interesting, never heard that concept before.