代码之家  ›  专栏  ›  技术社区  ›  nielsj

添加两个分数,为什么(次要)优化有效

  •  1
  • nielsj  · 技术社区  · 15 年前

    前几天我在我的代码库中添加了一个分数类(第一次,以前从来没有需要过分数类,我怀疑我现在做了什么,但到底是怎么回事…)。在写两个分数之间的加法时,我发现了一个小的优化,但它没有意义(从数学意义上说),为什么它是这样的。

    为了说明这一点,我将使用分数A和B,有效地分别由a、bn、ad和bd组成分子和分母。

    这里有两个用于gcd/lcm的函数,公式也在维基百科上。它们很简单,很容易理解。当然,LCM也可以是(A*B)/C。

    static unsigned int GreatestCommonDivisor(unsigned int A, unsigned int B)
    {
        return (!B) ? A : GreatestCommonDivisor(B, A % B);
    }
    
    static unsigned int LeastCommonMultiple(unsigned int A, unsigned int B)
    {
        const unsigned int gcDivisor = GreatestCommonDivisor(A, B);
        return (A / gcDivisor) * B;
    }
    

    首先,我们来看看第一种方法:

    least_common_mul = least_common_multiple(Ad, Bd)  
    new_nominator = An * (least_common_mul / Ad) + Bn * (least_common_mul / Bd)  
    new_denominator = least_common_mul  
    

    瞧,工作,显而易见,完成了。

    然后通过在记事本上的一些涂鸦,我发现了另一个有效的方法:

    greatest_common_div = greatest_common_divisor(Ad, Bd)  
    den_quot_a = Ad / greatest_common_div  
    den_quot_b = Bd / greatest_common_div  
    new_numerator = An * den_quot_b + Bn * den_quot_a  
    new_denominator = den_quot_a * Bd 
    

    现在,新的分母是相当明显的,因为它与LCD功能中的分母完全相同。其他的似乎也很有意义,除了交换了与原始分子相乘的正确因子,在这一行是具体的:

    new_numerator = An * den_quot_b + Bn * den_quot_a  
    

    为什么不是 A+B B?

    输入示例:5/12和11/18

    greatest_common_div = 6  
    den_quot_a = 12/6 = 2;  
    den_quot_b = 18/6 = 3;  
    new_numerator = 5*3 + 11*2 = 37;  
    new_denominator = 36; 
    
    2 回复  |  直到 15 年前
        1
  •  6
  •   Amber    15 年前

    很简单,你通常会做的就是让分数超过相同的分母-用每个分数的分子和分母乘以另一个分数分母中第一个分母中没有的因子。

    2是从18中缺失的36;3是从12中缺失的36。因此,您可以乘以:

    (5/12)  * (3/3)  ==>  15/36
    (11/18) * (2/2)  ==>  22/36
    
        2
  •  0
  •   Jason S    15 年前

    也许你错过了数论的一个恒等式…任何两个正数 m n ,

     m*n = gcd(m,n) * lcm(m,n)
    

    实例:

     4*18 = 2 * 36
     15*9 = 3 * 45
    

    找到A/B和C/D分数的公分母涉及使用LCM(b,d)或等效的b d/gcd(b,d)。