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.

[1] http://groups.google.com/group/comp.lang.javascript/…


You may also like these

Reading Local Files With Javascript

Security Conscious Javascript Normally, javascript does not have access to local files.  Rightfully so because almost every web server should be untrusted and allowing anybody to read your files is...

Manufacturing User Preferences For MCD

Nobody likes boring code Mozilla products like Thunderbird and Firefox represent setting choices in a textual “tree” system. (Read the intro.)  Preferences that begin with print. live on the tree...

Could be an Obstacle

Hi Reader, I am going to tell you the truth. I was not looking forward to writing the javascript necessary to get BrewSession going. For one thing I am a...

Related posts brought to you by Yet Another Related Posts Plugin.