Robert Eisele
Systems Engineer, Architect and DBA

Rational numbers in JavaScript

fraction.js is a new rational numbers library I published today. Floating point numbers, like double in JavaScript, are a very rough estimate of a real number, which has to deal with rational and irrational numbers the same way. Of course, it has the benefit of feeling very natural in the way you deal with those numbers. You can assign Math.PI, Math.sqrt(2) and 3 / 4 without thinking what the computer actually does.

The obvious downside of the way double is represented inside of the computer is the loss of precision.

When we remember some high-school math, we can easily avoid those problems. Introducing some kind of number theory makes the whole thing perfect. That's why I wrote fraction.js.

Assume you want to find a rational approximation of PI. There is a nice algorithm, which doesn't converge very fast, but serves good as an example here.

var PI = new Fraction(0);
var n = 1;
for (var i = 0; i < 100000; i++) {
	PI = PI.add(new Fraction(4).div(n));
	n+= 2;
	PI = PI.sub(new Fraction(4).div(n));
	n+= 2;
}
console.log(PI)

The result of this algorithm is

PI.n / PI.d = 17402216385200408 / 5539306332998545 = 3.14158765358987

Looks nice, doesn't it? In the README.md, which is shipped with the library, is another algorithm to approximate sqrt(5) - 2.

Test Fraction.js

Examples:
123/33 div 4.33
123.(345) mod 3.(1112)

Limits

So what is it all good for and where are the limits?

The library can be used whenever you have to do precise calculations with natural and rational numbers. Even if you don't use it in production, you can use it to pre-calculate numbers (as I did with PI above).

I tried not to force casting to real integers in the JavaScript source. This would have the limit of the smallest (unsigned) number of 1 / (Math.pow(2, 31) - 1) and the biggest number of (Math.pow(2, 31) - 1) / 1. The way it is implemented now, you work with doubles again - larger doubles, which shrinks the problem space.

Another obvious limit is the fact, that it is bound to rational numbers - as the name suggests. I've implemented a sqrt(n) function, but it is very inprecise, as it only gives an estimate. But in some optimization scenarios this is more than enough.

You might also be interested in the following

 

Sorry, comments are closed for this article. Contact me if you have an inventive contribution.