54

say we have fraction 2/4, it can be reduced to 1/2.

Is there a JavaScript function that can do the reducing?

Penny Liu
  • 15,447
  • 5
  • 79
  • 98
dave
  • 14,991
  • 26
  • 76
  • 110

8 Answers8

100
// Reduce a fraction by finding the Greatest Common Divisor and dividing by it.
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];
}

reduce(2,4);
// [1,2]

reduce(13427,3413358);
// [463,117702]
Phrogz
  • 296,393
  • 112
  • 651
  • 745
  • 2
    That is a very elegant `gcd` function. The only change I would suggest is some form of input checking for `NaN` as `gcd(NaN, 1)` produces `1` where I would expect `NaN` or an error. – zzzzBov Nov 09 '12 at 00:04
  • 2
    @zzzzBov An interesting edge case. Certainly one could add `if (isNaN(numerator) || isNaN(denominator)) return NaN;` as the first line. – Phrogz Jan 08 '13 at 15:35
  • 2
    fun fact, this solution uses Euclid's algorithm to find GCD: https://en.wikipedia.org/wiki/Euclidean_algorithm – pgarciacamou Jun 30 '17 at 23:00
  • Useful! Note that you may want to round the numerator to get fractions that don't exceed the denominator: `reduce(Math.round(.25 * 4), 4))` this will keep small (estimated) values pinned to the max denominator you give it. – dmarr Oct 16 '18 at 19:31
  • 5
    Works great but why specify the function name `gcd` twice, and then assign the numerical result to the same variable? That's bad JavaScript etiquette. – Rudey Dec 21 '20 at 00:03
10

No, but you can write one yourself fairly easily. Essentially you need to divide the top and bottom parts of the fraction by their 'Greatest Common Denominator'... Which you can calculate from Euclid's algorithm.

Read here for more info: http://www.jimloy.com/number/euclids.htm

edit:

code (because everyone seems to be doing it, this doesn't use recursion though)

var FractionReduce = (function(){
    //Euclid's Algorithm
    var getGCD = function(n, d){
        var numerator = (n<d)?n:d;
        var denominator = (n<d)?d:n;        
        var remainder = numerator;
        var lastRemainder = numerator;

        while (true){
            lastRemainder = remainder;
            remainder = denominator % numerator;
            if (remainder === 0){
                break;
            }
            denominator = numerator;
            numerator = remainder;
        }
        if(lastRemainder){
            return lastRemainder;
        }
    };

    var reduce = function(n, d){
        var gcd = getGCD(n, d);

        return [n/gcd, d/gcd];
    };

    return {
            getGCD:getGCD,
            reduce:reduce
           };

}());

alert(FractionReduce.reduce(3413358, 13427));
david
  • 17,925
  • 4
  • 43
  • 57
6

I know this is an old post, but I converted the accepted answer into a loop solution instead of a recursive function. This would be much more memory efficient and likely much faster (no memory stack operations and execution calls needed).

function reduce(numerator, denominator) {
    var a = numerator;
    var b = denominator;
    var c;
    while (b) {
        c = a % b; a = b; b = c;
    }
    return [numerator / a, denominator / a];
}

The memory footprint is just 5 Number structs, and a simple loop.

flamewave000
  • 547
  • 5
  • 12
5

To reduce a fraction, divide the numerator and denominator by the Greatest Common Factor. Phrogz and David have already provided the source code..

However if you're searching for javascript libraries for handling fractions, then here are a few to choose from.

  1. Fraction.js
  2. Math.Rational
  3. Ratio.js
  4. Rational.js

Here's an example using Ratio.js.

var a = Ratio(2,4);

a.toString() == "2/4";
a.simplify().toString() == "1/2";    // reduce() returns a clone of the Ratio()
a.toString() == "2/4"; // Ratio functions are non-destructive.
Larry Battle
  • 9,008
  • 4
  • 41
  • 55
  • Useful, thanks. I've posted a question asking about the relative efficiencies of these libraries here: http://stackoverflow.com/questions/15840390/what-is-the-most-efficient-fraction-library-in-javascript?noredirect=1#comment22538987_15840390 – Omn Apr 05 '13 at 18:04
  • 1
    @Omn So did you already profile the performance using jsperf.com? If you see any problems with Ratio.js when just open an ticket and I'll try to fix it. https://github.com/LarryBattle/Ratio.js – Larry Battle Apr 12 '13 at 16:14
  • I have no experience creating and running benchmarks. I ended up just going into the code and looking at what seemed to have better coding, comments, and implemented functions. I ended going with Ratio.js but I haven't had a chance to work on that project much since then. I'll certainly let you know if I find any issues and I may just contribute bug fixes if I can see the problem myself. – Omn Apr 12 '13 at 21:37
1

I know there is already an answer, but I want share a JS library that I found when I was looking something to convert decimal numbers into fractions and reducing fractions.

The library calls Fraction.js, which was really helpful for me and saved me a lot time and work. Hope it can be very useful to somebody else!

Hydrothermal
  • 4,851
  • 7
  • 26
  • 45
Jabel Márquez
  • 772
  • 1
  • 11
  • 38
0

Here is a recursive function using ECMAScript 6 reduce. It works for most fractions as long as the remainder isn't too small. 0 has been redefined to make it work for arrays like [1.2, 2.4, 12, 24]. I tested in Chrome and IE Edge so it may behave differently in other browsers or upgrades. So it should work with an array of floats.

 Array.prototype.gcd = function () {
   if (this.length === 0)
     return null;
   return this.reduce((prev, curr) => {
     if (curr <= 1.00000000001e-12)
       return prev
     else
       return [curr, prev % curr].gcd();
    });
  }

  var reducedValueGCD = [1.2, 2.4, 12, 24, 240].gcd();

Search for MDN reduce or more info here.

RetroCoder
  • 2,597
  • 10
  • 52
  • 81
0

Reduce a string fraction like "2/4" and output as string fraction.

function reduce([numerator, denominator]){
  for (let i = numerator; i > 0; i--) {
    if(!(numerator % i) && !(denominator % i)){
      return [(numerator / i), (denominator / i)];
    }
  }
}

function reduceFraction(string){
  return reduce(string.split('/').map(n => +n)).join('/');
}

one = '2/4';
two = '20/200';
three = '330/2050';

console.log('2/4 reduced to', reduceFraction(one));
console.log('20/200 reduced to', reduceFraction(two));
console.log('330/2050 reduced to', reduceFraction(three));
SoEzPz
  • 14,958
  • 8
  • 61
  • 64
0

In addition to Jan I would change his function to:

function reduce(numerator,denominator){
var roundNr = 0

if(numerator >= denominator) {
    roundNr = Math.floor(numerator / denominator);
    numerator -= (roundNr * denominator);
}

var gcd = function gcd(a,b){
        return b ? gcd(b, a%b) : a;
};
gcd = gcd(numerator,denominator);
return {roundNr: roundNr, numerator: numerator/gcd, denominator:        denominator/gcd};              }

This will also return the roundnumber when the numerator >= denominator.