Convert Fraction String to Decimal?
Asked Answered
F

19

37

I'm trying to create a javascript function that can take a fraction input string such as '3/2' and convert it to decimal—either as a string '1.5' or number 1.5

function ratio(fraction) {
    var fraction = (fraction !== undefined) ? fraction : '1/1',
    decimal = ??????????;
    return decimal;
});

Is there a way to do this?

Farceuse answered 22/8, 2011 at 2:37 Comment(3)
eval(fraction) would of course work, but only if you trust your input.Dicho
@Dicho And in this case I do—thank you!Farceuse
Note that there are many fractions that can't be exactly represented as decimal numbers (e.g. 1/3) and many decimals that can't be exactly represented in javascript: 0.0065 + 0.0005 = 0.006999999999999999;Bergstein
M
55

Since no one has mentioned it yet there is a quick and dirty solution:

var decimal = eval(fraction); 

Which has the perks of correctly evaluating all sorts of mathematical strings.

eval("3/2")    // 1.5
eval("6")      // 6
eval("6.5/.5") // 13, works with decimals (floats)
eval("12 + 3") // 15, you can add subtract and multiply too

People here will be quick to mention the dangers of using a raw eval but I submit this as the lazy mans answer.

Myocardiograph answered 22/8, 2011 at 2:49 Comment(8)
+1 since it is an easy solution and you have warned of the dangers.Anesthesiologist
@Nat This is exactly all I need in this case. Thx!Farceuse
Not lazy, it's what eval is meant for - evaluating expressions that aren't known until runtime.Bergstein
This is an old question, but I would like to understand what the dangers of using eval in this case would be? I'm new to JS but this solved my problem very nicely, however this is user inputted data so could this cause problems?Declivous
@Declivous eval is slow, and potentially dangerous. If the user can figure out a way to get you to call eval() on his string, then he can potentially do XSS with it.Juice
"since it is an easy solution and you have warned of the dangers" – but that's just it, he DOESN'T warn of the dangers. A complete answer would state why they shouldn't do this!Halfback
@Halfback Right. He didn't warn of -the- dangers. But he did mention there are dangers associated. For a list of -the- dangers we can all ask uncle google, or bing or whatever ;)Charil
There is no dangers with eval as long the code i simple and string can not be injected. The dangers is to downgrade our abilities and intellect. Everyone can see the string is only in the argument. There is no use of generelise or making imaginations of danger in this case. It is good to warn about eval in general if told it is safe and useful in this case. Eval is also safe in freezed objects and the parameters is safe. Provide a formal proof of safety and encapsulate it in IIFE function. Or should we remove eval from runtime? Should we remove runtime and computers because it can be unsafe?Peart
J
23

Here is the bare bones minimal code needed to do this:

var a = "3/2";
var split = a.split('/');
var result = parseInt(split[0], 10) / parseInt(split[1], 10);
alert(result); // alerts 1.5

JsFiddle: http://jsfiddle.net/XS4VE/

Things to consider:

  • division by zero
  • if the user gives you an integer instead of a fraction, or any other invalid input
  • rounding issues (like 1/3 for example)
Juice answered 22/8, 2011 at 2:42 Comment(2)
Thanks. That's pretty slick. I'll keep it in mind if I ever need the full deal, but right now all I need is the eval() method.Farceuse
No need for parseInt, just use split[0]/split[1].Bergstein
C
9

I have a function I use to handle integers, mixed fractions (including unicode vulgar fraction characters), and decimals. Probably needs some polishing but it works for my purpose (recipe ingredient list parsing).

Inputs "2 1/2", "2½", "2 ½", and "2.5" will all return 2.5. Examples:

var numQty = require("numeric-quantity");

numQty("1 1/4") === 1.25;  // true
numQty("3 / 4") === 0.75;  // true
numQty("¼" ) === 0.25;     // true
numQty("2½") === 2.5;      // true
numQty("¾") === 0.75;      // true
numQty("⅓") === 0.333;     // true
numQty("⅔") === 0.667;     // true

One thing it doesn't handle is decimals within the fraction, e.g. "2.5 / 5".

Cecilacecile answered 20/3, 2015 at 16:11 Comment(0)
F
7

Something like this:

bits = fraction.split("/");
return parseInt(bits[0],10)/parseInt(bits[1],10);
Felicita answered 22/8, 2011 at 2:40 Comment(0)
H
7

I created a nice function to do just that, everything was based off of this question and answers but it will take the string and output the decimal value but will also output whole numbers as well with out errors

https://gist.github.com/drifterz28/6971440

function toDeci(fraction) {
    fraction = fraction.toString();
    var result,wholeNum=0, frac, deci=0;
    if(fraction.search('/') >=0){
        if(fraction.search('-') >=0){
            wholeNum = fraction.split('-');
            frac = wholeNum[1];
            wholeNum = parseInt(wholeNum,10);
        }else{
            frac = fraction;
        }
        if(fraction.search('/') >=0){
            frac =  frac.split('/');
            deci = parseInt(frac[0], 10) / parseInt(frac[1], 10);
        }
        result = wholeNum+deci;
    }else{
        result = fraction
    }
    return result;
}

/* Testing values / examples */
console.log('1 ',toDeci("1-7/16"));
console.log('2 ',toDeci("5/8"));
console.log('3 ',toDeci("3-3/16"));
console.log('4 ',toDeci("12"));
console.log('5 ',toDeci("12.2"));
Harhay answered 14/10, 2013 at 16:14 Comment(0)
A
6

Too late, but can be helpful:

You can use Array.prototype.reduce instead of eval https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce

ES6

const fractionStrToDecimal = str => str.split('/').reduce((p, c) => p / c);
console.log(fractionStrToDecimal('1/4/2')); // Logs 0.125
console.log(fractionStrToDecimal('3/2')); // Logs 1.5

CJS

function fractionStrToDecimal(str) {
  return str.split('/').reduce((p, c) => p / c);
}
console.log(fractionStrToDecimal('1/4')); // Logs 0.25

[EDIT] Removed reducer initial value and now the function works for numerators greater than 1. Thanks, James Furey.

Autonomy answered 20/11, 2017 at 23:42 Comment(2)
Doesn't work for numerators greater than 1 (e.g. '3/2').Nadinenadir
You are right. Just removed the reducer initial value and it is working now. Thanks!Sites
N
5

Function (ES6):

function fractionToDecimal(fraction) {
  return fraction
    .split('/')
    .reduce((numerator, denominator, i) =>
      numerator / (i ? denominator : 1)
    );
}

Function (ES6, condensed):

function fractionToDecimal(f) {
  return f.split('/').reduce((n, d, i) => n / (i ? d : 1));
}

Examples:

fractionToDecimal('1/2');     // 0.5
fractionToDecimal('5/2');     // 2.5
fractionToDecimal('1/2/2');   // 0.25
fractionToDecimal('10/5/10'); // 0.2
fractionToDecimal('0/1');     // 0
fractionToDecimal('1/0');     // Infinity
fractionToDecimal('cat/dog'); // NaN
fractionToDecimal('42');      // 42
Nadinenadir answered 13/3, 2018 at 0:3 Comment(1)
This is great not only because it covers multiple divisions but also works for the case where there's no denominator which makes completely sense because a number can be thought of as a fraction with denominator 1.Tremble
W
3

With modern destructuring syntax, the best/safest answer can be simplified to:

const parseFraction = fraction => {
  const [numerator, denominator] = fraction.split('/').map(Number);
  return numerator / denominator;
}

// example
parseFraction('3/2'); // 1.5

In other words, split the faction by its / symbol, turn both resulting strings into numbers, then return the first number divided by the second ...

... all with only two (very readable) lines of code.

EDIT

The above assumes that for 1.5 you will only get 3/2 ... and not 1 1/2. But, as @Aro Parada noted in a comment, you might need to handle such whole numbers.

If so, you could use a very similar split-based approach, but with a reverse to handle the fact that we only sometimes have a whole number:

const parseFraction = fractionString => {
  const [fraction, wholeNumber = 0] = fractionString.trim().split(' ').reverse();
  const [numerator, denominator] = fraction.split('/').map(Number);
  return Number(wholeNumber) + numerator / denominator;
}

You might not even need the trim in there; strings like 1 1/2 will work even without it, but if you can have 1 1/2 you'll want to keep the trim.

Willable answered 26/9, 2022 at 0:2 Comment(2)
How would this work with something like 1 1/2Lomond
It wouldn't :( When I wrote that answer, I didn't have to worry about the 1 1/2 case ... but as it turns out (see my edit) the same basic approach can solve that case also.Willable
E
2

If you don't mind using an external library, math.js offers some useful functions to convert fractions to decimals as well as perform fractional number arithmetic.

console.log(math.number(math.fraction("1/3"))); //returns 0.3333333333333333
console.log(math.fraction("1/3") * 9) //returns 3
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjs/3.20.1/math.js"></script>
Evalyn answered 30/1, 2018 at 12:27 Comment(0)
C
2

const fractionStringToNumber = s => s.split("/").map(s => Number(s)).reduce((a, b) => a / b);

console.log(fractionStringToNumber("1/2"));
console.log(fractionStringToNumber("1/3"));
console.log(fractionStringToNumber("3/2"));
console.log(fractionStringToNumber("3/1"));
console.log(fractionStringToNumber("22/7"));
console.log(fractionStringToNumber("355 / 113"));
console.log(fractionStringToNumber("8/4/2"));

console.log(fractionStringToNumber("3")); // => 3, not "3"
Crypto answered 12/1, 2020 at 19:4 Comment(0)
A
2

From a readability, step through debugging perspective, this may be easier to follow:

// i.e. '1/2' -> .5
// Invalid input returns 0 so impact on upstream callers are less likely to be impacted
function fractionToNumber(fraction = '') {
    const fractionParts = fraction.split('/');
    const numerator = fractionParts[0] || '0';
    const denominator = fractionParts[1] || '1';
    const radix = 10;
    const number = parseInt(numerator, radix) / parseInt(denominator, radix);
    const result = number || 0;

    return result;
}
Anthozoan answered 18/3, 2020 at 16:37 Comment(1)
This code a good starting point depending how resilient/defensive/predictable you want to make it. This function screams unit testing to assert it works correctly in the scenarios you expect to handle.Anthozoan
B
1

To convert a fraction to a decimal, just divide the top number by the bottom number. 5 divided by 3 would be 5/3 or 1.67. Much like:

function decimal(top,bottom) {
    return (top/bottom)
}

Hope this helps, haha

Backache answered 20/2, 2013 at 0:28 Comment(0)
P
1

It works with eval() method but you can use parseFloat method. I think it is better! Unfortunately it will work only with that kind of values - "12.2" not with "5/8", but since you can handle with calculation I think this is good approach!

Physoclistous answered 21/1, 2014 at 12:55 Comment(0)
S
1

If you want to use the result as a fraction and not just get the answer from the string, a library like https://github.com/infusion/Fraction.js would do the job quite well.

var f = new Fraction("3/2");
console.log(f.toString()); // Returns string "1.5"
console.log(f.valueOf()); // Returns number 1.5

var g = new Fraction(6.5).div(.5);
console.log(f.toString()); // Returns string "13"
Stopoff answered 4/6, 2015 at 11:31 Comment(0)
B
1

Also a bit late to the party, but an alternative to eval() with less security issues (according to MDN at least) is the Function() factory.

var fraction = "3/2";
console.log( Function("return (" + fraction + ");")() );

This would output the result "1.5" in the console.

Also as a side note: Mixed fractions like 1 1/2 will not work with neither eval() nor the solution with Function() as written as they both stumble on the space.

Buber answered 25/7, 2018 at 21:40 Comment(0)
S
1

safer eval() according to MDN

const safeEval = (str) => {
   return Function('"use strict";return (' + str + ")")();
}

safeEval("1 1/2") // 1.5

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval#Do_not_ever_use_eval!

Succor answered 3/3, 2019 at 0:56 Comment(0)
B
1

This too will work:

let y = "2.9/59"
let a = y.split('')
let b = a.splice(a.indexOf("/"))
console.log(parseFloat(a.join('')))
a = parseFloat(a.join(''))
console.log(b)
let c = parseFloat(b.slice(1).join(''))
let d = a/c
console.log(d) // Answer for y fraction
Belaud answered 2/7, 2019 at 14:18 Comment(0)
S
1

I developed a function to convert a value using a factor that may be passed as a fraction of integers or decimals. The user input and conversion factor might not be in the correct format, so it checks for the original value to be a number, as well as that the conversion can be converted to a fraction assuming that /number means 1/number, or there are a numerator and a denominator in the format number/number.

/**
 * Convert value using conversion factor
 * @param {float} value - number to convert
 * @param {string} conversion - factor
 * @return {float} converted value
 */
function convertNumber(value, conversion) {
  try {
    let numberValue = eval(value);
    if (isNaN(numberValue)) {
      throw value + " is not a number.";
    }
    let fraction = conversion.toString();
    let divider = fraction.indexOf("/");
    let upper = 1;
    let denominator = 1;
    if (divider == -1) {
      upper = eval(fraction);
    } else {
      let split = fraction.split("/");
      if (split.length > 2) {
        throw fraction + " cannot be evaluated to a fraction.";
      } else {
        denominator = eval(split[1]);
        if (divider > 0) {
          upper = eval(split[0]);
        }
      }
    }
    let factor = upper/denominator;
    if (isNaN(factor)) {
      throw fraction + " cannot be converted to a factor.";
    }
    let result = numberValue * factor;
    if (isNaN(result)) {
      throw numberValue + " * " + factor + " is not a number.";
    }
    return result
  } catch (err) {
    let message = "Unable to convert '" + value + "' using '" + conversion + "'. " + err;
    throw message;
  }
}
Silky answered 18/3, 2021 at 18:58 Comment(0)
M
1

You can use eval() with regex to implement a secure method to calculate fraction

var input = "1/2";
return input.match(/^[0-9\/\.]+$/) != null ? eval(input) : "invalid number";

Mumps answered 27/8, 2022 at 2:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.