Inspired from a stackoverflow.com question.
Convert decimal amount to text string fraction in Javascript?
Code
/**
* @author Larry Battle
* @license MIT
* @version 1.0
* @date May 08, 2012
* @purpose To provide a function that converts a decimal to a simplified fraction.
* @info
*/
var mixin = {};
mixin.getKeys = function (obj) {
var props = [];
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
props.push(prop);
}
}
return props;
};
mixin.getFractionObject = (function () {
var obj = {
0 : '0',
1 : '1'
},
num = 10,
den = 11,
value;
while (--num) {
while (--den > 1) {
value = (num / den).toFixed(3);
if (value < 1) {
obj[value] = num + "/" + den;
}
}
den = 11;
}
obj.keys = mixin.getKeys(obj);
return function () {
return obj;
};
}
());
mixin.getClosestNum = function (arr, val) {
if (typeof arr !== "object" || !(arr.hasOwnProperty('length')) || isNaN(val)) {
return false;
}
var i = arr.length,
j = i - 1,
minDiff = Math.abs(+val - arr[j]),
diff;
while (i--) {
diff = Math.abs(+val - arr[i]);
if (diff < minDiff) {
minDiff = diff;
j = i;
}
}
return arr[j];
};
mixin.getFractionFromDecimal = function (dec) {
if (isNaN(dec) || !isFinite(dec)) {
return false;
}
if (!/\./.test(dec)) {
return dec;
}
var fracs = mixin.getFractionObject(),
matches = dec.toString().match(/(\d+)(\.\d+)/),
fraction = fracs[mixin.getClosestNum(fracs.keys, Math.abs(+matches[2]))],
sign = ( 0 < dec || (fraction == "0" && Math.abs(dec) < 1) ) ? '' : '-';
if (1 < Math.abs(dec)) {
if (isNaN(fraction)) {
fraction = +matches[1] + " " + fraction;
} else {
fraction = +matches[1] + (+fraction);
}
}
return sign + fraction;
};
Testcases and Demo
// Qunit Testcases
$(document).ready(function(){
var runAllTests = function () {
test("Test getKeys()", function () {
var obj = {};
deepEqual([], getKeys(obj), "Empty objects should have no props.");
obj.a = 1;
deepEqual(['a'], getKeys(obj), "a should be returned as a property.");
obj = {
1 : 1,
2 : 1,
3 : 1
}
deepEqual(['1', '2', '3'], getKeys(obj), "1,2,3 should be properties.");
});
test("Test getClosestNum()", function () {
var arr = [0, 1, 2, 3, 10, 99, 1000];
equal(false, getClosestNum({}, 1), "First argument must be an array.");
equal(false, getClosestNum(arr), "Second argument must be an defined.");
equal(false, getClosestNum(arr, {}), "Second argument must be an number.");
var runThisTest = function (nums, expect) {
var i = expect.length;
while (i--) {
equal(getClosestNum(nums, expect[i][0]), expect[i][1], expect[i][0] + " is the closest to " + expect[i][1]);
}
};
runThisTest(arr, [
[-10, 0],
[0.3, 0],
[0.5, 1],
[2.1, 2],
[10.1, 10],
[100, 99],
[600, 1000]
]);
});
test("Test getFractionObject()", function () {
var fracs = getFractionObject();
var props = getKeys( fracs );
areAllNumbers = true;
var i = props.length;
while( i-- ){
if( isNaN( props[ i ] ) ){
areAllNumbers = false;
}
}
ok( areAllNumbers, "getFractionObject() returns an object with all properties as a number." );
equal( fracs[ 0 ], "0", "0.500 should be 0" );
equal( fracs[ '0.333' ], "1/3", "0.333 should be 1/3" );
equal( fracs[ '0.500' ], "1/2", "0.500 should be 1/2" );
equal( fracs[ '0.900' ], "9/10", "0.900 should be 9/10" );
equal( fracs[ 1 ], "1", "0.500 should be 1" );
});
test("Test getFractionFromDecimal() with invalid inputs", function(){
equal(getFractionFromDecimal( "ten" ), false );
equal(getFractionFromDecimal( NaN ), false );
equal(getFractionFromDecimal( undefined ), false );
equal(getFractionFromDecimal( Infinity ), false );
});
test("Test getFractionFromDecimal() with only decimal values <= 1", function(){
equal(getFractionFromDecimal(0.001), "0" );
equal(getFractionFromDecimal(0.23), "2/9" );
equal(getFractionFromDecimal(0.335), "1/3" );
equal(getFractionFromDecimal(0.756), "3/4" );
equal(getFractionFromDecimal(0.995), "1" );
});
test("Test getFractionFromDecimal() with integers", function(){
equal(getFractionFromDecimal(12), "12" );
equal(getFractionFromDecimal(3), "3" );
});
test("Test getFractionFromDecimal() with negative values", function(){
equal(getFractionFromDecimal(-0.001), "0" );
equal(getFractionFromDecimal(-0.23), "-2/9" );
equal(getFractionFromDecimal(-0.335), "-1/3" );
equal(getFractionFromDecimal(-0.756), "-3/4" );
equal(getFractionFromDecimal(-0.995), "-1" );
});
test("Test getFractionFromDecimal() with numbers bigger than 1.", function(){
equal(getFractionFromDecimal(10.001), "10" );
equal(getFractionFromDecimal(-10.001), "-10" );
equal(getFractionFromDecimal(12.23), "12 2/9" );
equal(getFractionFromDecimal(3.335), "3 1/3" );
equal(getFractionFromDecimal(99.756), "99 3/4" );
equal(getFractionFromDecimal(34.995), "35" );
});
};
runAllTests();
});
Example
mixin.getFractionFromDecimal(-99.756); // returns "-99 3/4"
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
When we enter 1.0 then it shows 0 as a output which is incorrect, please verify it.
Not sure why. Try using Ratio.js instead. It's easier to use and well documented.
Ratio.js
http://larrybattle.github.io/Ratio.js/
Example:
Ratio.parse("1.0").toString() === "1/1";
Ratio.parse("1.0").toLocaleString() === "1";