Forum Moderators: open

Message Too Old, No Replies

Convert a decimal number to a fraction.

         

Armadillo

6:01 am on Aug 16, 2010 (gmt 0)

10+ Year Member



I need to convert decimal numbers to the nearest 1/x fraction.
I've tried several ways and it does great for numbers that have exactly 1/x solutions, but for others it yields things like 2/125 or 49/25000, etc.

I need to be able to give it any decimal number and get the nearest 1/x fraction.
Can you help with this?
Here is what I am currently using-
function decfrac(DtF)
{
var dec = DtF
var decString = dec.toString();
var dslength = decString.length - 1;
var div = 1;
// Multiply by powers of 10 to remove the decimal
for (i=0; i<dslength; i++)
{
dec = dec * 10;
div = div * 10;
}
// Factor out the GCF of the two numbers
for (i=2; i <= dec; i++) {
while ((mod(dec,i) == 0) && (mod(div,i) == 0))
{
dec = dec/i;
div = div/i;
}
}
expF = dec + "/" + div;
return expF;
}

function mod(n, m)
{
while (n >= m)
{
n = n-m;
}
return(n);
/*Keeps subtracting the number you want to divide by until the remainder is less than the original divisor, and then returning the remainder.
*/
}

birdbrain

2:25 pm on Aug 16, 2010 (gmt 0)



Hi there Armadillo,

if you require the numerator to always be "1", then the denominator more often than not will be a decimal. ;)

Here is an example...

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>

<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="language" content="english">
<meta http-equiv="Content-Style-Type" content="text/css">
<meta http-equiv="Content-Script-Type" content="text/javascript">

<title></title>

<style type="text/css">
label {
display:block;
margin-bottom:10px;
}
#fraction {
margin-top:10px;
}
</style>

<script type="text/javascript">

function decfrac(DtF) {

dec=DtF;
if((isNaN(dec))||(dec=='0.')){
alert('please insert some numbers in the box !');
df.reset();
return;
}
temp=dec;
dec=dec.toString().split('.')[1];
frac=Math.pow(10,dec.length)/parseFloat(dec);
obj.firstChild.nodeValue='the decimal='+temp+', the equivalent fraction=1/'+frac;
}

if(window.addEventListener){
window.addEventListener('load',init,false);
}
else {
if(window.attachEvent){
window.attachEvent('onload',init);
}
}

function init(){
df=document.forms[0];
obj=document.getElementById('fraction');
df[1].onclick=function() {
decfrac(document.forms[0][0].value);
}
df[2].onclick=function() {
obj.firstChild.nodeValue='';
}
}
</script>

</head>
<body>

<form action="#">
<div>
<label>decimal : <input type="text" value='0.'></label>
<input type="button" value="convert to fraction">
<input type="reset" value="clear result">
</div>
</form>

<div id="fraction">&nbsp;</div>

</body>
</html>

birdbrain

Fotiman

2:47 pm on Aug 16, 2010 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



Here is how I would approach it. Suppose you have the following decimal value:
0.12

0.12 = 0.12/1
The numerator (0.12) has 2 decimal places. To eliminate them, we need to multiply both the numerator and denominator (1) by 10^n (where n = the number of decimal places). So:
0.12/1 x 10^2/10^2 = 0.12/1 x 100/100 = 12/100

Note, 100/100 = 1, so we have not changed the original value any. 0.12 = 12/100.

Next we want the numerator value to be 1, so we're going to multiple our number by another fraction which is equal to (1/numerator)/(1/numerator):

12/100 x (1/12)/(1/12) = (12/12)/(100/12) = 1/8.(3)

Note, the denominator value is 8.3 repeating (8.3333333333...).
Note, (1/12)/(1/12) = 1, so again, we've not changed the value, just transformed it to a different fraction.

So, here's what we did:
1. Get the number of decimals
2. Multiplied the numerator and denominator by 10^n/10^n (10 to the nth power, where n is the number of decimals)
3. Divided the numerator and denominator by the numerator

function decimalPlaces(num) {
var decimalSeparator = '.',
tmp = num.toString(),
idx = tmp.indexOf(decimalSeparator);
if (idx >= 0) {
return (tmp.length - idx - 1);
}
return 0;
}
function decfrac(DtF) {
var n = decimalPlaces(DtF), // the number of decimals
m = Math.pow(10,n), // 10^n
numerator = DtF * m,
denominator = (numerator == 0 ? 0 : m / numerator);
numerator = (numerator == 0 ? 0 : numerator/numerator);
return (numerator == 0 ? "0" : numerator + "/" + denominator);
}


Hope that helps.

rocknbil

11:32 pm on Aug 16, 2010 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



That is so Zen it's almost scary. except . . . maybe I'm implementing it wrong, seems to give odd results. 1/3 gives 1/3.33333335, but .6 gives 1/1.66666667 (wouldn't 3/5 be more accurate than 2/3?) Seems to work for .5, .25. When whole numbers are included it also does weird stuff (which I guess id trivial, can just split them and tack them back on.)

Birdbrain's solution gives the same results. :-) Great minds and all . . .

added:


function fractional_part(input,output) {
if (document.getElementById(input) && document.getElementById(output)) {
var inp = document.getElementById(input).value;
if (isNaN(inp)) { alert('Enter a decimal number.'); }
else {
document.getElementById(output).value = decfrac(inp);
}
}
else { alert('Input and output objects not found.'); }
return false;
}


using

<form action="" onsubmit="return fractional_part('num','res');">
<p><label for="num">Enter a decimal:</label> <input type="text" name="num" id="num" size="12" value="">
<input type="submit" value="Get It"><br>
<label for="res">Result:</label> <input style="border:none;" type="text" name="res" id="res" size="48" value="" onfocus="this.blur();">
</p>
</form>

daveVk

12:11 am on Aug 17, 2010 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Is not the bottom line just, round( 1/value ) ? Assuming value is < 1 or fractional part of whole.

Fotiman

12:36 am on Aug 17, 2010 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



maybe I'm implementing it wrong, seems to give odd results. 1/3 gives 1/3.33333335, but .6 gives 1/1.66666667 (wouldn't 3/5 be more accurate than 2/3?) Seems to work for .5, .25. When whole numbers are included it also does weird stuff (which I guess id trivial, can just split them and tack them back on.)

I'm not sure what you mean... 1/3 is not valid decimal input, it's a fraction. Also not sure what you mean by 3/5 being more accurate than 2/3... are you talking about inputing 3/5?

Armadillo

2:13 am on Aug 17, 2010 (gmt 0)

10+ Year Member



Thank you all very much. :)

rocknbil

2:35 am on Aug 17, 2010 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



1/3 is not valid decimal input, it's a fraction.


I meant .3, see following .6 example. I guess I misinterpreted it,

to the nearest 1/x fraction.


But it sent me on a bit of a mission, converting to fractions from decimals is something I never played with. This seems to work, and simplifies the fractions from what I can tell. They don't have 1 as a numerator though. :-) Probably a simpler way (feel free to splice as a new thread if too far O.T.)


<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01
Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Decimal Numbers to Fraction</title>
<script type="text/javascript">
// input the decimal part, write output to output field
function fractional_part(input,output) {
if (document.getElementById(input) && document.getElementById(output)) {
var inp = document.getElementById(input).value;
if (isNaN(inp) || (inp.indexOf('.')==-1)) { alert('Enter a decimal number.'); }
else {
document.getElementById(output).value = decfrac(inp);
}
}
else { alert('Input and output objects not found.'); }
return false;
}
// Convert decimal to it's simplified fractional part
function decfrac(DtF) {
parts = DtF.split('.');
var decimal = (parts[1])?parts[1]:parts[0];
var whole = (parts[1])?parts[0]:null;
var n = decimal.length;
m = Math.pow(10,n);
g_com_denom=gcd(decimal,m);
fractional = decimal/g_com_denom + '/' + m/g_com_denom;
return (whole)?whole+' '+fractional:fractional;
}
// Get the greatest common denominators of the two parts
// Seems convoluted, but say, for 25 and 100 you get 5*5*5*5 . . .
function gcd(num,denom) {
var gcd=1;
var common_elements = [];
var num_factors=get_factors(num);
var denom_factors=get_factors(denom);
for (w=0;w<num_factors.length;w++) {
var common=0;
for (j=0;j<denom_factors.length;j++) {
if (num_factors[w]==denom_factors[j]) {
common=1;
continue;
}
}
if (common==1) { common_elements.push(num_factors[w]); }
}
for (w=0;w<common_elements.length;w++) {
gcd *= common_elements[w];
}
return gcd;
}
// Get the prime factors for any number
function get_factors(num) {
factors = [];
//var chk='';
var working=num;
var sfactor = 2;
while (sfactor*sfactor <= num) {
if ((working%sfactor == 0) && (working != 1)) {
factors.push(sfactor);
working = working/sfactor;
}
else { sfactor++; }
}
if (working !=1) { factors.push(working); }
return factors;
}
</script>
</head>
<body>
<h1>Decimal Numbers to Fractions</h1>
<form action="" onsubmit="return fractional_part('num','res');">
<p><label for="num">Enter a decimal:</label>
<input type="text" name="num" id="num" size="12" value="">
<input type="submit" value="Get It"><br>
<label for="res">Result:</label>
<input style="border:none;" type="text" name="res" id="res"
size="48" value="" onfocus="this.blur();">
</p>
</form>
</body>
</html>


Edit: Ahh, crappies, it fails on .625. It's close though.

Man, I wish they'd fix the style code thingy, [w] looks really stoopid as a counter. :-)

Fotiman

2:34 pm on Aug 17, 2010 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



If you wrap you code blocks in [code] blocks, then you can use i. :) I post all my code blocks in [quote][pre][code].

Now, if you want to display each fraction in it's lowest whole number form, then this is how I would do it (Note, the code for determining the Greatest Common Factor is quite simple). :)


<!DOCTYPE html>
<html>
<head>
<title>Decimal Numbers to Fraction</title>
</head>
<body>
<h1>Decimal Numbers to Fractions</h1>
<form action="#" onsubmit="return fractional_part('num','res');">
<div>
<label for="num">Enter a decimal:</label>
<input type="text" name="num" id="num" size="12" value="">
<input type="submit" value="Get It">
<br>
<label for="res">Result:</label>
<input type="text" name="res" id="res" size="24" value="" readonly >
</div>
</form>
<script type="text/javascript">
function decimalPlaces(num) {
var decimalSeparator = '.',
tmp = num.toString(),
idx = tmp.indexOf(decimalSeparator);
if (idx >= 0) {
return (tmp.length - idx - 1);
}
return 0;
}
function decfrac(DtF) {
var i,
j,
gcf,
n = decimalPlaces(DtF), // the number of decimals
m = Math.pow(10,n), // 10^n
numerator = Math.round(DtF * m), // Important to round the result
negative = numerator < 0,
denominator = 1 * (numerator != 0 ? m : 1)
// Save some work if numerator is zero
if (numerator == 0) {
return "0";
}
// Handle negative values
if (negative) {
// Temporarily convert to positive
numerator *= -1; // negative * negative = positive
}
// Get the Greatest Common Factor
for (i = (numerator > denominator ? numerator: denominator); i > 0; i--) {
if ((numerator % i == 0) && (denominator % i == 0)) {
gcf = i;
break;
}
}
numerator = numerator / gcf;
if (negative) {
// Convert back to negative
numerator *= -1;
}
denominator = denominator / gcf;
return numerator + "/" + denominator;
}
/**
* @param {String} input The id of the element containing the decimal input
* @param {String} output The id of the element to write the output to
*/
function fractional_part(input, output) {
var elIn = document.getElementById(input),
elOut = document.getElementById(output),
val;
// Some basic validation
if (elIn && elOut) {
val = elIn.value;
val = val.replace(/^\s+|\s+$/g,""); // trim off whitespace
if (isNaN(val) || val.length == 0) {
alert('Enter a decimal number.');
}
else {
// Do the math
elOut.value = decfrac(val);
}
}
else {
alert('Input and output elements not found.');
}
return false;
}
</script>
</body>
</html>


I also added Math.round to the numerator value because when working with decimal values, you might not always get the results you think you will. For example, .55 * 100 would give 55.00000000000001. I also modified the function to handle negative values as well.

rocknbil

6:16 pm on Aug 17, 2010 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



U da' man. :-P As usual, always making it harder than it has to be, I wrestled with the common factors too much. Slight mod that maintains the whole numbers for display, 1 1/4, 1 1/2, -1 5/8, etc. instead of 5/4, 3/2 . . . probably a better way to do that too.


function decfrac(DtF) {
var i,
j,
gcf,
whole = null,
n = decimalPlaces(DtF), // the number of decimals
m = Math.pow(10,n), // 10^n
numerator = Math.round(DtF * m), // Important to round the result
negative = numerator < 0,
denominator = 1 * (numerator != 0 ? m : 1);
// Save some work if numerator is zero
if (numerator == 0) {
return "0";
}
// Handle negative values
if (negative) {
// Temporarily convert to positive
numerator *= -1; // negative * negative = positive
}
// Get the Greatest Common Factor
for (i = (numerator > denominator ? numerator: denominator); i > 0; i--) {
if ((numerator % i == 0) && (denominator % i == 0)) {
gcf = i;
break;
}
}
if (Math.floor(numerator/denominator) > 0) {
whole=Math.floor(numerator/denominator);
numerator = numerator-(whole*denominator);
}
numerator = numerator / gcf;
if (negative) {
// Convert back to negative
if (whole) { whole *= -1; }
else { numerator *= -1; }
}
denominator = denominator / gcf;
fractional = numerator + "/" + denominator;
return (whole)?whole+' '+fractional:fractional;
}

Fotiman

6:49 pm on Aug 17, 2010 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



Nice. Here's my version. Almost the same as yours:


function decfrac(DtF) {
var i,
j,
gcf,
whole = 0,
n = decimalPlaces(DtF), // the number of decimals
m = Math.pow(10,n), // 10^n
numerator = Math.round(DtF * m), // Important to round the result
negative = numerator < 0,
denominator = 1 * (numerator != 0 ? m : 1)
// Save some work if numerator is zero
if (numerator == 0) {
return "0";
}
// Handle negative values
if (negative) {
// Temporarily convert to positive
numerator *= -1; // negative * negative = positive
}
// Get the Greatest Common Factor
for (i = (numerator > denominator ? numerator: denominator); i > 0; i--) {
if ((numerator % i == 0) && (denominator % i == 0)) {
gcf = i;
break;
}
}
numerator = numerator / gcf;
denominator = denominator / gcf;
if (numerator >= denominator) {
whole = Math.floor(numerator / denominator);
numerator = numerator % denominator;
}
return (negative ? "-" : "") +
(whole > 0 ? whole + " " : "") +
(numerator > 0 ? numerator + "/" + denominator : "");
}


The difference is that I check to see if the numerator is >= denominator (meaning there is a whole number), which should be slightly more efficient than calling Math.floor. I also then use the mod operator (%) to recalculate the numerator. And then rather than trying to convert the number back to a negative, I just decided to print a "-" in the return value rather than multiply by -1 again.