So i want to be able to convert any decimal number into fraction. In both forms such as one without remainder like this: 3/5
or with remainder: 3 1/4
Your first 2 steps are reasonable.
But what you should do is for the numerator and denominator calculate the Greatest Common Divisor (GCD) and then divide the numerator and denominator with that divisor to get the fraction you want.
GCD is rather easy to calculate. Here is Euclid's algorithm:
var gcd = function(a, b) {
if (!b) return a;
return gcd(b, a % b);
};
Edit
I've added a fully working JSFiddle.
Use the Euclidean algorithm to find the greatest common divisor.
function reduce(numerator,denominator){
var gcd = function gcd(a,b){
return b ? gcd(b, a%b) : a;
};
gcd = gcd(numerator,denominator);
return [numerator/gcd, denominator/gcd];
}
This will provide you with the following results on your console
reduce(2,4);
// [1,2]
reduce(13427,3413358);
// [463,117702]
So by continuing from already what you have,
var x = 34/35;
var a = x - x.toFixed();
var tens = Math.pow(10,a.toString().length - 2);
var numerator = tens * x;
var denominator = tens;
reduce(numerator,denominator);
Source: https://stackoverflow.com/a/4652513/1998725
You can use brute force test on different denominators and retain the result that has least error.
The algorithm below is an example of how you might go about this, but, suffers from being inefficient and limited to searching for denominators up to 10000.
function find_rational( value, maxdenom ) {
console.clear();
console.log( "Looking up: " + value );
let best = { numerator: 1, denominator: 1, error: Math.abs(value - 1) }
if ( !maxdenom ) maxdenom = 10000;
for ( let denominator = 1; best.error > 0 && denominator <= maxdenom; denominator++ ) {
let numerator = Math.round( value * denominator );
let error = Math.abs( value - numerator / denominator );
if ( error >= best.error ) continue;
best.numerator = numerator;
best.denominator = denominator;
best.error = error;
console.log( "Intermediate result: "
+ best.numerator + "/" + best.denominator
+ " (" + ( best.numerator/best.denominator)
+ " error " + best.error + " )" );
}
console.log( "Final result: " + JSON.stringify( best ) );
return best;
}
function calc() {
const value = parseFloat( $("#myInput").val() );
if ( isNaN(value) ) {
$( "#myResult" ).val( "NaN" );
return;
}
const rational = find_rational( value, 10000 );
$("#myResult").val( rational.numerator
+ " / " + rational.denominator
+ " ( Error: " + rational.error + " )" );
}
calc();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<P>
Enter a decimal number:<BR/>
<INPUT type="text" name="myInput" id="myInput" value=".3435" onkeyup="calc()"/><BR/>
</P>
<P>
Resulting Rational:<BR/>
<INPUT name="myResult" id="myResult" value=""/><BR/>
</P>
The above determines the .3435 as a fraction is 687 / 2000.
Also, had you gave it PI (e.g. 3.1415926) it produces good looking fractions like 22/7 and 355/113.
I came up with this for 16ths
function getfract(theNum){
var input=theNum.toString();
var whole = input.split(".")[0];
var rem = input.split(".")[1] * .1;
return(whole + " " + Math.round(rem * 16) + "/16");
}
I get very poor results using the GCD approach. I got much better results using an iterative approach.
For example, here is a very crude approach that zeros in on a fraction from a decimal:
function toFraction(x, tolerance) {
if (x == 0) return [0, 1];
if (x < 0) x = -x;
if (!tolerance) tolerance = 0.0001;
var num = 1, den = 1;
function iterate() {
var R = num/den;
if (Math.abs((R-x)/x) < tolerance) return;
if (R < x) num++;
else den++;
iterate();
}
iterate();
return [num, den];
}
The idea is you increment the numerator if you are below the value, and increment the denominator if you are above the value.
The tricky bit is not letting floating points get carried away.
Converting a number to a string restrains the trailing digits,
especially when you have a decimal with an integer, like 1.0625.
You can round off clumsy fractions, by passing a precision parameter.
Often you want to force a rounded value up, so a third parameter can specify that.
(e.g.; If you are using a precision of 1/64, the smallest return for a non-zero number will be 1/64, and not 0.)
Math.gcd= function(a, b){
if(b) return Math.gcd(b, a%b);
return Math.abs(a);
}
Math.fraction= function(n, prec, up){
var s= String(n),
p= s.indexOf('.');
if(p== -1) return s;
var i= Math.floor(n) || '',
dec= s.substring(p),
m= prec || Math.pow(10, dec.length-1),
num= up=== 1? Math.ceil(dec*m): Math.round(dec*m),
den= m,
g= Math.gcd(num, den);
if(den/g==1) return String(i+(num/g));
if(i) i= i+' and ';
return i+ String(num/g)+'/'+String(den/g);
}
Math.roundFraction(.3435,64); value: (String) 11/32