{"id":1047,"date":"2012-05-08T18:09:37","date_gmt":"2012-05-09T00:09:37","guid":{"rendered":"http:\/\/bateru.com\/news\/?p=1047"},"modified":"2012-05-09T12:04:27","modified_gmt":"2012-05-09T18:04:27","slug":"code-of-the-day-javascript-convert-decimal-to-a-simplified-fraction","status":"publish","type":"post","link":"https:\/\/bateru.com\/news\/2012\/05\/code-of-the-day-javascript-convert-decimal-to-a-simplified-fraction\/","title":{"rendered":"Code of the Day: Javascript, Convert decimal to a simplified fraction"},"content":{"rendered":"<p>Inspired from a stackoverflow.com question.<br \/>\n<a href=\"http:\/\/stackoverflow.com\/questions\/7249195\/convert-decimal-amount-to-text-string-fraction-in-javascript\">Convert decimal amount to text string fraction in Javascript?<\/a><\/p>\n<p><b>Code<\/b><\/p>\n<pre lang='javascript'>\r\n\/**\r\n * @author Larry Battle <http:\/\/bateru.com\/news\/contact-me>\r\n * @license MIT\r\n * @version 1.0\r\n * @date May 08, 2012\r\n * @purpose To provide a function that converts a decimal to a simplified fraction.\r\n * @info <http:\/\/bateru.com\/news\/2012\/05\/code-of-the-day-javascript-convert-decimal-to-a-simplified-fraction\/>\r\n *\/\r\nvar mixin = {};\r\nmixin.getKeys = function (obj) {\r\n    var props = [];\r\n    for (var prop in obj) {\r\n        if (obj.hasOwnProperty(prop)) {\r\n            props.push(prop);\r\n        }\r\n    }\r\n    return props;\r\n};\r\nmixin.getFractionObject = (function () {\r\n    var obj = {\r\n        0 : '0',\r\n        1 : '1'\r\n    },\r\n    num = 10,\r\n    den = 11,\r\n    value;\r\n    while (--num) {\r\n        while (--den > 1) {\r\n            value = (num \/ den).toFixed(3);\r\n            if (value < 1) {\r\n                obj[value] = num + \"\/\" + den;\r\n            }\r\n        }\r\n        den = 11;\r\n    }\r\n    obj.keys = mixin.getKeys(obj);\r\n    return function () {\r\n        return obj;\r\n    };\r\n}\r\n    ());\r\nmixin.getClosestNum = function (arr, val) {\r\n    if (typeof arr !== \"object\" || !(arr.hasOwnProperty('length')) || isNaN(val)) {\r\n        return false;\r\n    }\r\n    var i = arr.length,\r\n    j = i - 1,\r\n    minDiff = Math.abs(+val - arr[j]),\r\n    diff;\r\n    while (i--) {\r\n        diff = Math.abs(+val - arr[i]);\r\n        if (diff < minDiff) {\r\n            minDiff = diff;\r\n            j = i;\r\n        }\r\n    }\r\n    return arr[j];\r\n};\r\nmixin.getFractionFromDecimal = function (dec) {\r\n    if (isNaN(dec) || !isFinite(dec)) {\r\n        return false;\r\n    }\r\n    if (!\/\\.\/.test(dec)) {\r\n        return dec;\r\n    }\r\n    var fracs = mixin.getFractionObject(),\r\n    matches = dec.toString().match(\/(\\d+)(\\.\\d+)\/),\r\n    fraction = fracs[mixin.getClosestNum(fracs.keys, Math.abs(+matches[2]))],\r\n    sign = ( 0 < dec || (fraction == \"0\" &#038;&#038; Math.abs(dec) < 1) ) ? '' : '-';\r\n    if (1 < Math.abs(dec)) {\r\n        if (isNaN(fraction)) {\r\n            fraction = +matches[1] + \" \" + fraction;\r\n        } else {\r\n            fraction = +matches[1] + (+fraction);\r\n        }\r\n    }\r\n    return sign + fraction;\r\n};\r\n<\/pre>\n<p><b>Testcases and Demo<\/b><br \/>\n<iframe style=\"width: 100%; height: 300px\" src=\"http:\/\/jsfiddle.net\/tWyHg\/4\/embedded\/\" allowfullscreen=\"allowfullscreen\" frameborder=\"0\"><\/iframe><\/p>\n<pre lang='javascript'>\r\n\/\/ Qunit Testcases\r\n$(document).ready(function(){\r\n\tvar runAllTests = function () {\r\n\t\ttest(\"Test getKeys()\", function () {\r\n\t\t\tvar obj = {};\r\n\t\t\tdeepEqual([], getKeys(obj), \"Empty objects should have no props.\");\r\n\t\t\tobj.a = 1;\r\n\t\t\tdeepEqual(['a'], getKeys(obj), \"a should be returned as a property.\");\r\n\t\t\tobj = {\r\n\t\t\t\t1 : 1,\r\n\t\t\t\t2 : 1,\r\n\t\t\t\t3 : 1\r\n\t\t\t}\r\n\t\t\tdeepEqual(['1', '2', '3'], getKeys(obj), \"1,2,3 should be properties.\");\r\n\t\t});\r\n\t\ttest(\"Test getClosestNum()\", function () {\r\n\t\t\tvar arr = [0, 1, 2, 3, 10, 99, 1000];\r\n\t\t\tequal(false, getClosestNum({}, 1), \"First argument must be an array.\");\r\n\t\t\tequal(false, getClosestNum(arr), \"Second argument must be an defined.\");\r\n\t\t\tequal(false, getClosestNum(arr, {}), \"Second argument must be an number.\");\r\n\t\t\tvar runThisTest = function (nums, expect) {\r\n\t\t\t\tvar i = expect.length;\r\n\t\t\t\twhile (i--) {\r\n\t\t\t\t\tequal(getClosestNum(nums, expect[i][0]), expect[i][1], expect[i][0] + \" is the closest to \" + expect[i][1]);\r\n\t\t\t\t}\r\n\t\t\t};\r\n\t\t\trunThisTest(arr, [\r\n\t\t\t\t\t[-10, 0],\r\n\t\t\t\t\t[0.3, 0],\r\n\t\t\t\t\t[0.5, 1],\r\n\t\t\t\t\t[2.1, 2],\r\n\t\t\t\t\t[10.1, 10],\r\n\t\t\t\t\t[100, 99],\r\n\t\t\t\t\t[600, 1000]\r\n\t\t\t\t]);\r\n\t\t});\r\n\t\ttest(\"Test getFractionObject()\", function () {\r\n\t\t\tvar fracs = getFractionObject();\r\n\t\t\tvar props = getKeys( fracs );\r\n\t\t\t\r\n\t\t\tareAllNumbers = true;\r\n\t\t\tvar i = props.length;\r\n\t\t\twhile( i-- ){\r\n\t\t\t\tif( isNaN( props[ i ] ) ){\r\n\t\t\t\t\tareAllNumbers = false;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tok( areAllNumbers, \"getFractionObject() returns an object with all properties as a number.\" );\r\n\t\t\tequal( fracs[ 0 ], \"0\", \"0.500 should be 0\" );\r\n\t\t\tequal( fracs[ '0.333' ], \"1\/3\", \"0.333 should be 1\/3\" );\r\n\t\t\tequal( fracs[ '0.500' ], \"1\/2\", \"0.500 should be 1\/2\" );\r\n\t\t\tequal( fracs[ '0.900' ], \"9\/10\", \"0.900 should be 9\/10\" );\r\n\t\t\tequal( fracs[ 1 ], \"1\", \"0.500 should be 1\" );\r\n\t\t});\r\n\t\ttest(\"Test getFractionFromDecimal() with invalid inputs\", function(){\r\n\t\t\tequal(getFractionFromDecimal( \"ten\" ), false );\r\n\t\t\tequal(getFractionFromDecimal( NaN ),  false );\r\n\t\t\tequal(getFractionFromDecimal( undefined ),  false );\r\n\t\t\tequal(getFractionFromDecimal( Infinity ),  false );\r\n\t\t});\r\n\t\ttest(\"Test getFractionFromDecimal() with only decimal values <= 1\", function(){\r\n\t\t\tequal(getFractionFromDecimal(0.001), \"0\" );\r\n\t\t\tequal(getFractionFromDecimal(0.23), \"2\/9\" );\r\n\t\t\tequal(getFractionFromDecimal(0.335), \"1\/3\" );\r\n\t\t\tequal(getFractionFromDecimal(0.756), \"3\/4\" );\r\n\t\t\tequal(getFractionFromDecimal(0.995), \"1\" );\r\n\t\t});\r\n\t\ttest(\"Test getFractionFromDecimal() with integers\", function(){\r\n\t\t\tequal(getFractionFromDecimal(12), \"12\" );\r\n\t\t\tequal(getFractionFromDecimal(3), \"3\" );\r\n\t\t});\r\n\t\ttest(\"Test getFractionFromDecimal() with negative values\", function(){\r\n\t\t\tequal(getFractionFromDecimal(-0.001), \"0\" );\r\n\t\t\tequal(getFractionFromDecimal(-0.23), \"-2\/9\" );\r\n\t\t\tequal(getFractionFromDecimal(-0.335), \"-1\/3\" );\r\n\t\t\tequal(getFractionFromDecimal(-0.756), \"-3\/4\" );\r\n\t\t\tequal(getFractionFromDecimal(-0.995), \"-1\" );\r\n\t\t});\r\n\t\ttest(\"Test getFractionFromDecimal() with numbers bigger than 1.\", function(){\r\n\t\t\tequal(getFractionFromDecimal(10.001), \"10\" );\r\n\t\t\tequal(getFractionFromDecimal(-10.001), \"-10\" );\r\n\t\t\tequal(getFractionFromDecimal(12.23), \"12 2\/9\" );\r\n\t\t\tequal(getFractionFromDecimal(3.335), \"3 1\/3\" );\r\n\t\t\tequal(getFractionFromDecimal(99.756), \"99 3\/4\" );\r\n\t\t\tequal(getFractionFromDecimal(34.995), \"35\" );\r\n\t\t});\r\n\t};\r\n\trunAllTests();\r\n});\r\n<\/pre>\n<p><b>Example<\/b><br \/>\nmixin.getFractionFromDecimal(-99.756); \/\/ returns  \"-99 3\/4\"<\/p>\n","protected":false},"excerpt":{"rendered":"<p>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 &hellip; <a href=\"https:\/\/bateru.com\/news\/2012\/05\/code-of-the-day-javascript-convert-decimal-to-a-simplified-fraction\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Code of the Day: Javascript, Convert decimal to a simplified fraction<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[11],"tags":[30,164,137],"class_list":["post-1047","post","type-post","status-publish","format-standard","hentry","category-frontend-tech","tag-code-of-the-day","tag-javascript","tag-stackoverflow-com"],"_links":{"self":[{"href":"https:\/\/bateru.com\/news\/wp-json\/wp\/v2\/posts\/1047","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/bateru.com\/news\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/bateru.com\/news\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/bateru.com\/news\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/bateru.com\/news\/wp-json\/wp\/v2\/comments?post=1047"}],"version-history":[{"count":4,"href":"https:\/\/bateru.com\/news\/wp-json\/wp\/v2\/posts\/1047\/revisions"}],"predecessor-version":[{"id":1052,"href":"https:\/\/bateru.com\/news\/wp-json\/wp\/v2\/posts\/1047\/revisions\/1052"}],"wp:attachment":[{"href":"https:\/\/bateru.com\/news\/wp-json\/wp\/v2\/media?parent=1047"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/bateru.com\/news\/wp-json\/wp\/v2\/categories?post=1047"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/bateru.com\/news\/wp-json\/wp\/v2\/tags?post=1047"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}