This post improves the code at “Code of the Day Javascript Decimal to fraction” by using Euclid’s Algorithm to find the Great Common Factor or GCF, aka GCD. This method provides a speed up of 10x when compared to the original algorithm posted.
Code
/**
*@function gcd (aka Euclid's algorithm)
*@purpose returns the greatest common factor between two numbers;
*/
function gcd(a, b) {
return (b) ? gcd(b, a % b) : a;
}
/**
*@function dec2Frac
*@purpose returns a decimal as a fraction.
*/
var dec2Frac = function ( num ) {
var top = num.toString().replace(/\d+[.]/, '');
var bot = Math.pow(10, top.length);
if (num > 1) {
top = +top + Math.floor(num) * bot;
}
var x = gcd(top, bot);
return (top / x) + "/" + (bot / x);
};
Usage
dec2Frac( 1.24325 ) // returns "4973/4000"
dec2Frac( 2.45 ) // returns "49/20"
Speed Test between Version 1 and 2 of dec2Frac()
//@requires Firebug or Chrome Developer Tools
//The following code test the speed difference between the Version 1 and 2 of dec2Frac.
function gcd(a, b) {
return (b) ? gcd(b, a % b) : a;
}
var dec2FracV2 = function (d) {
var top = d.toString().replace(/\d+[.]/, '');
var bot = Math.pow(10, top.length);
if (d > 1) {
top = +top + Math.floor(d) * bot;
}
var x = gcd(top, bot);
return (top / x) + "/" + (bot / x);
};
function dec2FracV1(d) {
var df = 1, top = 1, bot = 1;
var limit = 1e5; //Increase the limit to get more precision.
while (df != d && limit-- > 0) {
if (df < d) {
top += 1;
}
else {
bot += 1;
top = parseInt(d * bot, 10);
}
df = top / bot;
}
return top + '/' + bot;
}
var getRandomNum = function (i, decLen) {
return (Math.random() * (i || 1)).toFixed(decLen);
};
var runTest = function ( funcName ) {
var func = { "V1": dec2FracV1, "V2": dec2FracV2 }[ funcName ];
var i = 1000;
while (i--) {
num = getRandomNum(10, 4);
var x = func(num);
if (num != eval(x)) {
console.warn("ERROR: Function %s, The fraction %s != %s", funcName, num, x);
}
}
};
console.time( 'V1' );
runTest( "V1" );
console.timeEnd( 'V1' );
console.time( 'V2' );
runTest( "V2" );
console.timeEnd( 'V2' );
Chrome Result:
V1: 11628ms
V2: 185ms
Try the test out yourself
jsbin.com
What REALLY is Data Science? Told by a Data Scientist - By Joma Tech
Writing perfect code is a challenging process. That's where code reviews come in to help…
"The Next Leap: How A.I. will change the 3D industry - Andrew Price - Blender"
"Captain Disillusion: World's Greatest Blenderer - Live at the Blender Conference 2018 - CaptainDisillusion"
My 5 Favorite Linux Shell Tricks for SPEEEEEED (and efficiency) - By tutoriaLinux > What's…
View Comments
This works great, although I don't understand how it works. I went further and took my quantity and split it out so I can display it as a whole number with an integer, like this:
qtywhole = Math.floor(qty); //the whole integar part of the number
qtyfraction = dec2Frac(qty % 1); //the fraction part of the number
qtywhole = (qtywhole!=0 ? qtywhole : ''); //don't display whole number if it's 0
qtyfraction = (qtyfraction!=0 && qtyfraction!='0/1' ? qtyfraction : ''); //don't display fraction if it's 0
return qtywhole + ' ' + qtyfraction;
So your above example gets output as 2 9/20 instead of 49/20.
The only problem is I need to find a way for it to round the fraction so that it will only have a denominator of 2 or 3 or 4, because I'm using this for a recipe, so I don't want people to have to try to measure something like 3/8 cups.
I've found a way to round the input decimal to either the nearest 1/4 or 1/3 (whichever is closer), but dec2Frac still spits out fractions like 3333333333333333/10000000000000000, which needs to somehow be changed to 1/3.
Any ideas?
Thanks! Phil
Check out Ratio.js - Fractions for javascript, https://github.com/LarryBattle/Ratio.js/
I updated Ratio.js to include a function called `.toQuantityOf()`, which will pick the best approximate ratio/fraction that represents the original value.
Usage using your Example:
var val = 3/8;
Ratio.parse(val).toQuantityOf(2,3,4).reduce().toString() === "1/3"
Demo here:
http://jsfiddle.net/PNxr3/
Another demo but more basic,
http://larrybattle.github.com/Ratio.js/demo/demo-basic.html
Tell your friends and blog about Ratio.js if you like it. :)
I hope that helps.
Thanks Larry. I'm not a coder and I just couldn't figure out the Ratio.js thing at all, so I went my own route, but I spent a few hours with your scripts and they taught me a lot about javascript, so thanks again!
Open up a ticket and I can try to help you. https://github.com/LarryBattle/Ratio.js/issues?state=open