It is a pretty well known fact that using javascript to add decimals 0.1 with 0.2 does not result in 0.3. ^{[1]} Try it yourself with the FireBug console. For the uninitiated, the problem stems from javascript’s internal representation of numbers. They are actually binary numbers that are usually exact, but sometimes for example, are *0.00000000000000004* off. This is particularly aggravating when writing calculators that rely on js to give accurate results.

In my text inputs I was using toFixed() and some magic HTML attributes to keep decimals nice and clean. However, this method breaks down when a user enters a number with more significant figures than initially set up or you try to operate on two numbers with different sig figs. It was probably inevitable that I use a little arithmetic library extending *Number* to make decimals play nice.

Since javascript is 13 years old I thought it would be a simple thing to find such a library. I was wrong. After four days learning, looking and lamenting I had no library. After putting this one together in about a day and a half I am not surprised that nobody published theirs. Most of the eleven functions are one-liners, yet it bothers me that there are probably thirty-odd implementations of the this out there and not one found through Google.

// decimal_arithmetic.js String.prototype.digitsAfterDecimal = function() { var parts = this.split(".", 2); // FIXME: Not international! if( ! parts[1] ) { parts[1] = ""; } return parts[1].length; }; Number.prototype.biggerScalar = function(n) { return n.scale() > this.scale() ? n.scale() : this.scale(); }; Number.prototype.digitsAfterDecimal = function() { return this.toString().digitsAfterDecimal(); }; Number.prototype.divided = function(n) { return this.dividedBy(n); }; Number.prototype.dividedBy = function(n) { return this.multiply( n.reciprocal() ); }; Number.prototype.minus = function(n) { return this.plus( n.negative() ); }; Number.prototype.multiply = function(n) { var s = this.biggerScalar(n); return (Math.round(s*this,0) * Math.round(s*n,0)) / (s*s); }; Number.prototype.negative = function() { return -1 * this; }; Number.prototype.plus = function(n) { var s = this.biggerScalar(n); return (Math.round(s*this,0) + Math.round(s*n,0)) / s; }; Number.prototype.reciprocal = function() { return 1 / this; }; Number.prototype.scale = function() { return Math.pow(10, this.digitsAfterDecimal() ); }; |

Now you can do magical things like:

0.1.plus(0.2) // 0.3 |

yielding the correct results.

I am looking forward to javascript 2.0 when I can override the + operator. Maybe I won’t go that far since binary arithmetic is still faster.