convert decimal number to fraction in javascript or closest fraction [duplicate] - javascript

This question already has answers here:
How to simplify a decimal into the smallest possible fraction?
(6 answers)
Closed last year.
The community reviewed whether to reopen this question last year and left it closed:
Original close reason(s) were not resolved
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.
what i was doing is this..
lets say i have number .3435.
Calculate amount of digits after decimals.
multiply by 10 with power of the amount before number.
then somehow find greatest common factor.
Now i don't know how to find GCF. And nor i know how to implement logic to find fraction that represents a number closely or in remainder form if exact fraction doesn't exists.
code i have so far: (testing)
x = 34/35;
a = x - x.toFixed();
tens = (10).pow(a.toString().length - 2);
numerator = tens * x;
denominator = tens;

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.

Unless you are willing to work on developing something yourself then I would suggest using a library that someone has already put effort into, like fraction.js
Javascript
var frac = new Fraction(0.3435);
console.log(frac.toString());
Output
687/2000
On jsFiddle

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.

One quick and easy way of doing it is
getFraction = (decimal) => {
for(var denominator = 1; (decimal * denominator) % 1 !== 0; denominator++);
return {numerator: decimal * denominator, denominator: denominator};
}

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.

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

I had researched all over the website and I did combine all code into one, Here you go!
function fra_to_dec(num){
var test=(String(num).split('.')[1] || []).length;
var num=(num*(10**Number(test)))
var den=(10**Number(test))
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];
}
return (reduce(num,den)[0]+"/"+reduce(num,den)[1])
}
This code is very easy to use! You can even put number in this function!

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

Inspired by #chowey answer, which contained recursive implementation of finding close fraction for a decimal value within given tolerance, here is better (see benchmark), iterative version of it.
function toFractionIterative(x, epsilon = 0.0001) {
if (x == 0) return [0, 1];
const a = Math.abs(x);
let n = 0;
let d = 1;
let r;
while (true) {
r = n / d;
if (Math.abs((r - a) / a) < epsilon) {
break;
}
if (r < a) {
n++;
}
else {
d++;
}
}
return [x < 0 ? -n : n, d];
}
Benchmark (tl;dr: recursive 1,589 ops/s, iterative 5,955 ops/s; use iterative approach)

let v = 3.141592;
document.write(d2f(v)); // 392699/125000
function d2f(v) // decimal to fraction
{
if (Math.floor(v) == v) return v + '/' + 1;
v = Math.abs(v);
let ret = .01, // rounding error tolerance
td = v-Math.floor(v), // trailing digits
r = 1/td, // reciprocal
d = r, // start building denominator
lim = 20; // max loop limit
for (let i = 0; i < lim; i++)
{
td = r-Math.floor(r);
if (Math.abs(r-Math.round(r)) < ret) break;
r = 1/td;
d *= r;
}
return Math.round(d*v) + '/' + Math.round(d);
}

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");
}

function decimalToFraction(num) {
let numsAfterDecPoint = num.toString().split('.')[1] ? num.toString().split('.')[1].length : 0;
let numerator = num * Math.pow(10, numsAfterDecPoint);
let denominator = Math.pow(10, numsAfterDecPoint);
console.log(numerator + " / " + denominator)
let d = GCD(numerator,denominator)
return numerator / d + " / " + denominator / d
}
console.log(decimalToFraction(0.5)); // 5 / 10 => 1 / 2
console.log(decimalToFraction(178.45)); // 17845 / 100 => 3569 / 20
function GCD(a,b) {
let r = 0;
while(b != 0) {
r = a % b
a = b;
b = r;
}
return a;
}

Related

A code wars challenge

I have been struggling with this challenge and can't seem to find where I'm failing at:
Some numbers have funny properties. For example:
89 --> 8¹ + 9² = 89 * 1
695 --> 6² + 9³ + 5⁴= 1390 = 695 * 2
46288 --> 4³ + 6⁴+ 2⁵ + 8⁶ + 8⁷ = 2360688 = 46288 * 51
Given a positive integer n written as abcd... (a, b, c, d... being digits) and a positive integer p we want to find a positive integer k, if it exists, such as the sum of the digits of n taken to the successive powers of p is equal to k * n. In other words:
Is there an integer k such as : (a ^ p + b ^ (p+1) + c ^(p+2) + d ^ (p+3) + ...) = n * k
If it is the case we will return k, if not return -1.
Note: n, p will always be given as strictly positive integers.
digPow(89, 1) should return 1 since 8¹ + 9² = 89 = 89 * 1
digPow(92, 1) should return -1 since there is no k such as 9¹ + 2² equals 92 * k
digPow(695, 2) should return 2 since 6² + 9³ + 5⁴= 1390 = 695 * 2
digPow(46288, 3) should return 51 since 4³ + 6⁴+ 2⁵ + 8⁶ + 8⁷ = 2360688 = 46288 * 51
I'm new with javascript so there may be something off with my code but I can't find it. My whole purpose with this was learning javascript properly but now I want to find out what I'm doing wrong.I tried to convert given integer into digits by getting its modulo with 10, and dividing it with 10 using trunc to get rid of decimal parts. I tried to fill the array with these digits with their respective powers. But the test result just says I'm returning only 0.The only thing returning 0 in my code is the first part, but when I tried commenting it out, I was still returning 0.
function digPow(n, p){
// ...
var i;
var sum;
var myArray= new Array();
if(n<0)
{
return 0;
}
var holder;
holder=n;
for(i=n.length-1;i>=0;i--)
{
if(holder<10)
{
myArray[i]=holder;
break;
}
myArray[i]=holder%10;
holder=math.trunc(holder/10);
myArray[i]=math.pow(myArray[i],p+i);
sum=myArray[i]+sum;
}
if(sum%n==0)
{
return sum/n;
}
else
{
return -1;
}}
Here is the another simple solution
function digPow(n, p){
// convert the number into string
let str = String(n);
let add = 0;
// convert string into array using split()
str.split('').forEach(num=>{
add += Math.pow(Number(num) , p);
p++;
});
return (add % n) ? -1 : add/n;
}
let result = digPow(46288, 3);
console.log(result);
Mistakes
There are a few problems with your code. Here are some mistakes you've made.
number.length is invalid. The easiest way to get the length of numbers in JS is by converting it to a string, like this: n.toString().length.
Check this too: Length of Number in JavaScript
the math object should be referenced as Math, not math. (Note the capital M) So math.pow and math.trunc should be Math.pow and Math.trunc.
sum is undefined when the for loop is iterated the first time in sum=myArray[i]+sum;. Using var sum = 0; instead of var sum;.
Fixed Code
I fixed those mistakes and updated your code. Some parts have been removed--such as validating n, (the question states its strictly positive)--and other parts have been rewritten. I did some stylistic changes to make the code more readable as well.
function digPow(n, p){
var sum = 0;
var myArray = [];
var holder = n;
for (var i = n.toString().length-1; i >= 0; i--) {
myArray[i] = holder % 10;
holder = Math.trunc(holder/10);
myArray[i] = Math.pow(myArray[i],p+i);
sum += myArray[i];
}
if(sum % n == 0) {
return sum/n;
} else {
return -1;
}
}
console.log(digPow(89, 1));
console.log(digPow(92, 1));
console.log(digPow(46288, 3));
My Code
This is what I did back when I answered this question. Hope this helps.
function digPow(n, p){
var digPowSum = 0;
var temp = n;
while (temp > 0) {
digPowSum += Math.pow(temp % 10, temp.toString().length + p - 1);
temp = Math.floor(temp / 10);
}
return (digPowSum % n === 0) ? digPowSum / n : -1;
}
console.log(digPow(89, 1));
console.log(digPow(92, 1));
console.log(digPow(46288, 3));
You have multiple problems:
If n is a number it is not going to have a length property. So i is going to be undefined and your loop never runs since undefined is not greater or equal to zero
for(i=n.length-1;i>=0;i--) //could be
for(i=(""+n).length;i>=0;i--) //""+n quick way of converting to string
You never initialize sum to 0 so it is undefined and when you add the result of the power calculation to sum you will continually get NaN
var sum; //should be
var sum=0;
You have if(holder<10)...break you do not need this as the loop will end after the iteration where holder is a less than 10. Also you never do a power for it or add it to the sum. Simply remove that if all together.
Your end code would look something like:
function digPow(n, p) {
var i;
var sum=0;
var myArray = new Array();
if (n < 0) {
return 0;
}
var holder;
holder = n;
for (i = (""+n).length - 1; i >= 0; i--) {
myArray[i] = holder % 10;
holder = Math.trunc(holder / 10);
myArray[i] = Math.pow(myArray[i], p + i);
sum = myArray[i] + sum;
}
if (sum % n == 0) {
return sum / n;
} else {
return -1;
}
}
Note you could slim it down to something like
function digPow(n,p){
if( isNaN(n) || (+n)<0 || n%1!=0) return -1;
var sum = (""+n).split("").reduce( (s,num,index)=>Math.pow(num,p+index)+s,0);
return sum%n ? -1 : sum/n;
}
(""+n) simply converts to string
.split("") splits the string into an array (no need to do %10 math to get each number
.reduce( function,0) call's the array's reduce function, which calls a function for each item in the array. The function is expected to return a value each time, second argument is the starting value
(s,num,index)=>Math.pow(num,p+index+1)+s Fat Arrow function for just calling Math.pow with the right arguments and then adding it to the sum s and returning it
I have created a code that does exactly what you are looking for.The problem in your code was explained in the comment so I will not focus on that.
FIDDLE
Here is the code.
function digPow(n, p) {
var m = n;
var i, sum = 0;
var j = 0;
var l = n.toString().length;
var digits = [];
while (n >= 10) {
digits.unshift(n % 10);
n = Math.floor(n / 10);
}
digits.unshift(n);
for (i = p; i < l + p; i++) {
sum += Math.pow(digits[j], i);
j++;
}
if (sum % m == 0) {
return sum / m;
} else
return -1;
}
alert(digPow(89, 1))
Just for a variety you may do the same job functionally as follows without using any string operations.
function digPow(n,p){
var d = ~~Math.log10(n)+1; // number of digits
r = Array(d).fill()
.map(function(_,i){
var t = Math.pow(10,d-i);
return Math.pow(~~((n%t)*10/t),p+i);
})
.reduce((p,c) => p+c);
return r%n ? -1 : r/n;
}
var res = digPow(46288,3);
console.log(res);

Can't get BBP formula to work in nodejs

I've been trying to make a little program that can compute the n-th digit of pi.
After a few searches I've found that the most common formula is the BBP formula, wich is n-th digit = 16^-n[4/(8n + 1)-2/(8n + 4)-1/(8n + 5)-1/(8n + 6)].
The output is in base 16.
My code is the following:
function run(n) {
return Math.pow(16, -n) * (4 / (8 * n + 1) - 2 / (8 * n + 4) - 1 / (8 * n + 5) - 1 / (8 * n + 6));
}
function convertFromBaseToBase(str, fromBase, toBase) {
var num = parseInt(str, fromBase);
return num.toString(toBase);
}
for (var i = 0; i < 10; i++) {
var a = run(i);
console.log(convertFromBaseToBase(a, 16, 10));
}
So far, my output is the following:
1:3
2:0
3:0
4:0
5:1
6:7
7:3
8:1
9:7
10:3
Obviously, these are not the 10 first digits of PI.
My understanding is that values get rounded too often and that causes huge innacuracy in the final result.
However, I could be wrong, that's why I'm here to ask if I did anything wrong or if it's nodejs's fault. So I would loove if one of you guys have the answer to my problem!
Thanks!!
Unfortunately, 4/(8n + 1) - 2/(8n + 4) - 1/(8n + 5) - 1/(8n + 6) does not directly return the Nth hexadecimal digit of pi. I don't blame you, I made the same assumption at first. Although all the terms do indeed sum to pi, each individual term does not represent an individual hexadecimal digit. As seen here, the algorithm must be rewritten slightly in order to function correctly as a "digit spigot". Here is what your new run implementation ought to look like:
/**
Bailey-Borwein-Plouffe digit-extraction algorithm for pi
<https://en.wikipedia.org/wiki/Bailey%E2%80%93Borwein%E2%80%93Plouffe_formula#BBP_digit-extraction_algorithm_for_.CF.80>
*/
function run(n) {
var partial = function(d, c) {
var sum = 0;
// Left sum
var k;
for (k = 0; k <= d - 1; k++) {
sum += (Math.pow(16, d - 1 - k) % (8 * k + c)) / (8 * k + c);
}
// Right sum. This converges fast...
var prev = undefined;
for(k = d; sum !== prev; k++) {
prev = sum;
sum += Math.pow(16, d - 1 - k) / (8 * k + c);
}
return sum;
};
/**
JavaScript's modulus operator gives the wrong
result for negative numbers. E.g. `-2.9 % 1`
returns -0.9, the correct result is 0.1.
*/
var mod1 = function(x) {
return x < 0 ? 1 - (-x % 1) : x % 1;
};
var s = 0;
s += 4 * partial(n, 1);
s += -2 * partial(n, 4);
s += -1 * partial(n, 5);
s += -1 * partial(n, 6);
s = mod1(s);
return Math.floor(s * 16);
}
// Pi in hex is 3.243f6a8885a308d313198a2e037073...
console.log(run(0) === 3); // 0th hexadecimal digit of pi is the leading 3
console.log(run(1) === 2);
console.log(run(2) === 4);
console.log(run(3) === 3);
console.log(run(4) === 15); // i.e. "F"
Additionally, your convertFromBaseToBase function is more complicated than it needs to be. You have written it to accept a string in a specific base, but it is already being passed a number (which has no specific base). All you should really need is:
for (var i = 0; i < 10; i++) {
var a = run(i);
console.log(a.toString(16));
}
Output:
3
2
4
3
f
6
a
8
8
8
I have tested this code for the first 30 hexadecimal digits of pi, but it might start to return inaccurate results once Math.pow(16, d - 1 - k) grows beyond Number.MAX_SAFE_INTEGER, or maybe earlier for other reasons. At that point you may need to implement the modular exponentiation technique suggested in the Wikipedia article.

Converting a Decimal to a Fraction

I'm working on a "toy problem" where I am supposed to write a JavaScript function that converts a decimal into a fraction and returns it as a string. For example: fractionConverter(2.75) should return "11/4".
Here is my code:
function fractionConverter (number) {
if (number > 0) {
var isNegative = false;
} else if (number < 0) {
var isNegative = true;
}
number = Math.abs(number);
if (number % 1 === 0) {
var finalFrac = number + "/1";
} else {
for (var i = 2; i < 10000000000; i++) {
if ((i * number) % 1 === 0) {
var finalFrac = (i * number) + "/" + i;
}
if (finalFrac) { break; }
}
}
var getFrac = function(numString, bool) {
if (!bool) {
return numString;
} else {
return "-" + numString;
}
}
return getFrac(finalFrac, isNegative);
}
Sorry about the formatting. Anyway, I'm getting a weird spec failure. The function returns the correct values for the following numbers: 0.5, 3, 2.5, 2.75, -1.75 and .88. For some reason, however, it is failing on 0.253213. It is returning 1266065/5000000 instead of 253213/1000000. Not really sure why.
Thanks
I am just improving #william's answer,
I think this script gives you more reduced fraction.
function fractionConverter(number) {
var fraction = number - Math.floor(number);
var precision = Math.pow(10, /\d*$/.exec(new String(number))[0].length);
var getGreatestCommonDivisor = function(fraction, precision) {
if (!precision)
return fraction;
return getGreatestCommonDivisor(precision, fraction % precision);
}
var greatestCommonDivisor = getGreatestCommonDivisor(Math.round(fraction * precision), precision);
var denominator = precision / getGreatestCommonDivisor(Math.round(fraction * precision), precision);
var numerator = Math.round(fraction * precision) / greatestCommonDivisor;
function reduce (numer,denom) {
for (var i = 2; i >= 9; i++) {
if ((numer%i===0) && (denom%i)===0) {
numerator=numer/i;
denominator=denom/i;
reduce(numerator,denominator);
};
};
}
reduce(numerator,denominator);
return numerator + "/" + denominator;
}
document.getElementById("output").innerHTML = fractionConverter(0.24888);
Here is the HTML
<body>
<p id="output"></p>
</body>
</html>
Javascript doesn't deal with floating point numbers accurately.
I tried typing this into node:
0.253213 * 1000000
And I got this:
253213.00000000003
Here is a different approach to testing for a multiplier
var bigNumber = Math.pow(10,8);
var isDivisible = (Math.round(i * number * bigNumber)/bigNumber % 1) == 0;
This will help you some of the way.
This also work the way you might expect it to, if you wanted 0.333333333 to be treated as 1/3.
One issue is that the highest integer you can have is javascript is between 10^15 and 10^16.
If ((number * bigNumber) > 2^53) this will not work.
The caveat to this answer is that ECMAscript inadequately handles Decimals.
Also, note that the following is largely pseudocode, but should work with minor fixes.
Here is a javascript solution to this problem:
var decimal_to_fraction = {
"numerator": 0,
"denominator": 0,
"simplified_numerator": this.numerator,
"simplified_denominator": this.denominator,
"init": function(numerator, denominator){
this.numerator = numerator
this.denominator = denominator
},
"get_divisor": function(numerator, denominator){
var divisor = 0;
var divisors = [1, 2, 3, 4, 5];
for (i in divisors) {
if (!(numerator % divisor) && !(denominator % divisor)) {
divisor = i;
break
}
}
return divisor
},
"calculate_fraction": function() {
var simplified = false;
divisor = this.get_divisor(numerator_denominator);
if (divisor) {
while (simplified == false) {
if (this.simplfieid_numerator / divisor and this.simplified_denominator / divisor) {
this.simplified_numerator = simplified_numerator / divisor
this.simplified_denominator = simplified_denominator / divisor
} else {
simplified = true
}
}
}
return (this.simplified_numerator, this.simplfieid_denominator)
},
"get_fraction": function() {
this.calculate_fraction()
fraction = "{0} / {1}".format(this.simplfieid_numerator, this.simplified_denominator"
return fraction
}
}
decimal_to_fraction.get_fraction()
In case you were curious, here's a Python solution to your problem:
class DecimalToFraction(object):
def __init__(decimal):
self.numerator = decimal * 100
self.denominator = 100
self.simplified_numerator = self.numerator
self.simplified_denominator = self.denominator
def get_divisor(self, numerator, denominator):
divisor = 0
for i in range(0,5):
if not numerator % divisor and not denominator % divisor:
divisor = i
break
return divisor
def calculate_fraction(self):
simplified = False
divisor = get_divisor(self.numerator, self.denominator)
if divisor:
while simplified == False:
if self.simplified_numerator / divisor and self.simplfieid_denominator / divisor:
self.simplified_numerator = simplified_numerator / divisor
self.simplified_denominator = simplified_denominator / divisor
else:
simplified = True
return (self.simplified_numerator, self.simplified_denominator)
def get_fraction(self):
self.calculate_fraction()
fraction = "{0} / {1}".format(self.simplified_numerator, self.simplified_denominator)
return fraction
#d2f = DecimalToFraction(<decimal>)
#d2f.get_fraction()
I completely changed the structure of your code, but this solution does work. It is based off of code from this thread. I hope this helps.
function fractionConverter(number) {
var fraction = number - Math.floor(number);
var precision = Math.pow(10, /\d*$/.exec(new String(number))[0].length);
var getGreatestCommonDivisor = function(fraction, precision) {
if (!precision)
return fraction;
return getGreatestCommonDivisor(precision, fraction % precision);
}
var greatestCommonDivisor = getGreatestCommonDivisor(Math.round(fraction * precision), precision);
var denominator = precision / greatestCommonDivisor;
var numerator = Math.round(fraction * precision) / greatestCommonDivisor;
return numerator + "/" + denominator;
}
document.getElementById("output").innerHTML = fractionConverter(0.253213);
<!DOCTYPE html>
<html>
<body>
<p id="output"></p>
</body>
</html>
You can use Erik Garrison's fraction.js library to do that and more fractional operations.
To to do 1.75 , you can just do
var f = new Fraction(1.75);
console.log(f.toFraction()); // Results "1 3/4"
console.log(f.s * f.n + " / " + f.d); // Results "7 / 4"
console.log(f.toString()); // Results "1.75

Unexpected result when converting decimal to fraction

function gcd(a, b) {
return (b) ? gcd(b, a % b) : a;
}
var dec2Frac = 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);
var r1 = top / x;
var r2 = bot / x;
var frac = r1 + "/" + r2;
var parts = frac.split('/');
var simpler = parts[0][0]+'/'+parts[1][0];
return simpler;
};
If I input 640x960 = 0.66666666666667
I'm expecting the result to be 2/3 as evident here: http://www.mindspring.com/~alanh/fracs.html
Instead this function returns 6/1. Test here: http://jsbin.com/asoxud/1/
As an addition to MvG's Answer,
I found this quite interesting and wanted to understand how floating points are stored and how to get back an fraction of a float to maybe do calculations with them.
It gave a bit of brainache trying to figure this out on my own, but as it made click, i came up with this Fraction function,
I don't know if this helps you or not, but
now that its written anyway , why not leave it here
function Fraction(n, d) {
if ("number" !== typeof n)
throw new TypeError("Excptected Parameter to be of type number");
var strings = n.toString(2).split("."); //Split the number by its decimal point
if (strings.length > 1 && !d) { //No denominator given and n is a float
var floats = [strings[1].substr(0, 27), strings[1].substr(27, 54)]; //Split into to parts
var int64 = [
parseInt(floats[0], 2) << 1,
parseInt(floats[1], 2) << 1
];
var denominator = Math.pow(2, strings[1].length + 1); //
var numerator = int64[0] * Math.pow(2, floats[1].length);
numerator += int64[1];
numerator += parseInt(strings[0], 2) * denominator;
this.numerator = numerator;
this.denominator = denominator;
this.reduce();
this.approx = approx(n);
} else if (strings.length < 2 && !d) { // If no denominator and n is an int
this.numerator = n;
this.denominator = 1;
} else { //if n and d
this.numerator = n;
this.denominator = d;
}
function approx(f, n) {
n = n || 0;
var fraction = new Fraction(1, 1);
var float = Math.pow(f, -1);
var rec = ~~float;
var decimal = float - rec;
if (float.toPrecision(Fraction.precision) == rec)
return new Fraction(1, rec);
var _fraction = approx(decimal, n + 1);
fraction.denominator = rec * _fraction.denominator + _fraction.numerator;
fraction.numerator = _fraction.denominator;
return fraction;
}
}
//The approx precision
Fraction.precision = 10;
Fraction.prototype.toString = function () {
return this.numerator + "/" + this.denominator;
};
Fraction.prototype.gcd = function () {
return (function gcd(u, v) {
return ((u > 0) ? gcd(v % u, u) : v);
})(this.numerator, this.denominator);
};
Fraction.prototype.reduce = function () {
var _gcd = this.gcd();
this.numerator /= _gcd;
this.denominator /= _gcd;
};
Fraction.prototype.valueOf = function () {
return this.numerator / this.denominator;
};
var f = new Fraction(0.3333);
+ f; //0.3333333333
f.toString(); // 6004799502560181/18014398509481984
+ f.approx //0.33333
+ f.approx.toString() //3333/10000
var g = new Fraction(2 / 3);
+ g; //0.6666666666666666
g.toString(); //6004799503160661/9007199254740992
+ g.approx //0.6666666666666666
+ g.approx.toString() //2/3
Heres a JSbin as well
Your floating point numbers are approximations of the rational numbers you hope for. See e.g. Is floating point math broken? for details on this. The upshoot is: you can't hope to actually find a numerator and denominator which represent your original fraction.
If you want that fraction, you should have a look at continued fractions. Each truncated continued fraction will represent the best possible rational approximation for an arbitrary value. You can continue this until the error is sufficiently small.
Here is a page visualizing this approximation. The text is in German, but the maths should be clear enough. This page is in English but doesn't have as much visualization.

Adding Decimal place into number with javascript

I've got this number as a integer 439980
and I'd like to place a decimal place in 2 places from the right. to make it 4399.80
the number of characters can change any time, so i always need it to be 2 decimal places from the right.
how would I go about this?
thanks
function insertDecimal(num) {
return (num / 100).toFixed(2);
}
Just adding that toFixed() will return a string value, so if you need an integer it will require 1 more filter. You can actually just wrap the return value from nnnnnn's function with Number() to get an integer back:
function insertDecimal(num) {
return Number((num / 100).toFixed(2));
}
insertDecimal(99552) //995.52
insertDecimal("501") //5.01
The only issue here is that JS will remove trailing '0's, so 439980 will return 4399.8, rather than 4399.80 as you might hope:
insertDecimal(500); //5
If you're just printing the results then nnnnnn's original version works perfectly!
notes
JavaScript's Number function can result in some very unexpected return values for certain inputs. You can forgo the call to Number and coerce the string value to an integer by using unary operators
return +(num / 100).toFixed(2);
or multiplying by 1 e.g.
return (num / 100).toFixed(2) * 1;
TIL: JavaScript's core math system is kind of weird
Another Method
function makeDecimal(num){
var leftDecimal = num.toString().replace('.', ''),
rightDecimal = '00';
if(leftDecimal.length > 2){
rightDecimal = leftDecimal.slice(-2);
leftDecimal = leftDecimal.slice(0, -2);
}
var n = Number(leftDecimal+'.'+rightDecimal).toFixed(2);
return (n === "NaN") ? num:n
}
makeDecimal(3) // 3.00
makeDecimal(32) // 32.00
makeDecimal(334) // 3.34
makeDecimal(13e+1) // 1.30
Or
function addDecimal(num){
var n = num.toString();
var n = n.split('.');
if(n[1] == undefined){
n[1] = '00';
}
if(n[1].length == 1){
n[1] = n[1]+'0';
}
return n[0]+'.'+n[1];
}
addDecimal(1); // 1.00
addDecimal(11); // 11.00
addDecimal(111); // 111.00
Convert Numbers to money.
function makeMoney(n){
var num = n.toString().replace(/\$|\,/g,'');
if(isNaN(num))
num = "0";
sign = (num == (num = Math.abs(num)));
num = Math.floor(num*100+0.50000000001);
cents = num%100;
num = Math.floor(num/100).toString();
if(cents<10)
cents = "0" + cents;
for (var i = 0; i < Math.floor((num.length-(1+i))/3); i++)
num = num.substring(0,num.length-(4*i+3))+','+num.substring(num.length-(4*i+3));
return (((sign)?'':'-') + '$' + num + '.' + cents);
}
One More.
function addDecimal(n){
return parseFloat(Math.round(n * 100) / 100).toFixed(2);
}

Categories

Resources