有没有一种JavaScript函数可以简化分数?

54

假设我们有一个分数 2/4,可以将其化简为 1/2

是否有一种 JavaScript 函数可以进行化简操作?

8个回答

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]

2
这是一个非常优雅的gcd函数。我唯一建议的更改是对于'NaN'进行某种形式的输入检查,因为'gcd(NaN,1)'会产生'1',而我希望得到的是'NaN'或错误提示。 - zzzzBov
2
@zzzzBov 一个有趣的边缘情况。当然,可以将 if (isNaN(numerator) || isNaN(denominator)) return NaN; 添加为第一行。 - Phrogz
2
有趣的事实,这个解决方案使用欧几里得算法来找到最大公约数:https://en.wikipedia.org/wiki/Euclidean_algorithm - pgarciacamou
有用!请注意,您可能希望四舍五入分子,以获得不超过分母的分数:reduce(Math.round(.25 * 4), 4)) 这将使小(估计)值固定在您给出的最大分母上。 - dmarr
5
功能正常,但为什么要两次指定函数名称“gcd”,然后将数字结果分配给同一变量?这是不良的JavaScript规范。 - Rudey

10
不行,但是你可以很容易地自己编写一个。 基本上,您需要将分数的顶部和底部部分除以它们的“最大公约数”...您可以从欧几里得算法中计算出来。更多信息请参见此处:http://www.jimloy.com/number/euclids.htm
编辑:代码(因为每个人似乎都在这样做,但这不使用递归)
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));

6

我知道这是一个旧帖子,但是我将被采纳的答案转换成了循环解决方案,而不是递归函数。这样会更加节省内存,并且可能会更快(无需进行内存堆栈操作和执行调用)。

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];
}

内存占用仅为5个Number结构和一个简单的循环。


5
要简化一个分数,将分子和分母都除以最大公约数。 Phrogz和David已经提供了源代码。
然而,如果你正在寻找处理分数的JavaScript库,那么这里有几个可以选择的。
  1. Fraction.js
  2. Math.Rational
  3. Ratio.js
  4. Rational.js
这是一个使用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.

非常有用,谢谢。我在这里发布了一个问题,询问这些库的相对效率:http://stackoverflow.com/questions/15840390/what-is-the-most-efficient-fraction-library-in-javascript?noredirect=1#comment22538987_15840390 - Omn
1
@Omn 你已经使用jsperf.com对性能进行了分析吗?如果你在使用Ratio.js时遇到任何问题,只需打开一个工单,我会尽力解决。https://github.com/LarryBattle/Ratio.js - Larry Battle
我没有创建和运行基准测试的经验。最终,我只是进入代码并查看哪些代码、注释和实现函数更好。我最终选择了Ratio.js,但自那以后我还没有机会在该项目上工作。如果我发现任何问题,我一定会告诉你,如果我能自己看到问题,我可能会贡献错误修复。 - Omn

1
我知道已经有一个答案了,但是我想分享一个JS库,当我在寻找将十进制数转换为分数和约简分数的东西时,我发现了它。
该库名为Fraction.js,对我非常有帮助,节省了很多时间和工作量。希望它能对其他人也非常有用!

0

这里是一个使用 ECMAScript 6 reduce 的递归函数。只要余数不太小,它就适用于大多数分数。0 已被重新定义,以使其适用于像 [1.2、2.4、12、24] 这样的数组。我在 Chrome 和 IE Edge 中进行了测试,因此它在其他浏览器或升级中可能会有所不同。所以它应该可以处理浮点数数组。

 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();

搜索 MDN 的 reduce 或者更多信息 在这里


0
将形如“2/4”的字符串分数化简并输出为字符串分数。

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


0

除了Jan之外,我会更改他的函数为:

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

当分子>=分母时,这也将返回roundnumber。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接