除欧几里德之外的最常见的除数算法

时间:2013-10-17 09:31:24

标签: c# greatest-common-divisor

我应该基本上生成3种不同的算法来找到GCD(a,b)。

其中一个是Euclid的版本,所以我还需要两个。

实施在C#中完成。

建议?

4 个答案:

答案 0 :(得分:0)

(请注意,在计算gcd(a,b)时,我们可以假设a <= b;如果不是这样,我们可以交换它们。)

欧几里德算法无疑是计算gcd的最有效方法。但是如果你需要另外两种(效率低下)的方法来计算gcd(a,b),那么就有很多:

  1. a开始向下,测试每个号码,看它是否将ab分开。

  2. Prime-factorize ab(获取素数的多重集合),并返回这些多重集合的交集。

  3. 找到a的所有除数,并测试它们是否从b开始划分a并向下移动。

  4. 通过测试lcm(a,b)哪个可被b, 2*b, 3*b, ...整除,然后返回a来查找a*b/(lcm(a,b))

  5. 1和4可能最容易实现,因为它们不涉及分解。

    注意一些边缘情况也很重要:gcd(0,x) = x适用于所有x > 0,而gcd(0,0)未定义。从技术上讲,我认为gcd(a,b) = gcd(abs(a), abs(b))涵盖了输入可能为负的情况。

答案 1 :(得分:0)

这是最常用的三种算法:

public static uint FindGCDModulus(uint value1, uint value2)
{
while(value1 != 0 && value2 != 0)
{
        if (value1 > value2)
        {
                value1 %= value2;
        }
        else
        {
                value2 %= value1;
        }
}
return Math.Max(value1, value2);
   }

public static uint FindGCDEuclid(uint value1, uint value2)
  {
while(value1 != 0 && value2 != 0)
{
        if (value1 > value2)
        {
                value1 -= value2;
        }
        else
        {
                value2 -= value1;
        }
}
return Math.Max(value1, value2);
}

 public static uint FindGCDStein(uint value1, uint value2)
 {
if (value1 == 0) return value2;
if (value2 == 0) return value1;
if (value1 == value2) return value1;

bool value1IsEven = (value1 & 1u) == 0;
bool value2IsEven = (value2 & 1u) == 0;

if (value1IsEven && value2IsEven)
{
        return FindGCDStein(value1 >> 1, value2 >> 1) << 1;
}
else if (value1IsEven && !value2IsEven)
{
        return FindGCDStein(value1 >> 1, value2);
}
else if (value2IsEven)
{
        return FindGCDStein(value1, value2 >> 1);
}
else if (value1 > value2)
{
        return FindGCDStein((value1 - value2) >> 1, value2);
}
else
{
        return FindGCDStein(value1, (value2 - value1) >> 1);
}
}

答案 2 :(得分:0)

这是其中一种选择:

public static int gcd(int x, int y) {
    int result = 0;

    if (x<0) {
        x = -x;
    }
    if (y<0) {
        y = -y;
    }
    if (x == 0){
        result = y; 
    }
    if (y == 0){
        result = x; 
    }
    for (int i = 1; i < x+1; i++) {

        if ( x % i == 0) {

            if ( y % i == 0) {
                result = i;
            }
        }   
    } 
    return result; }

答案 3 :(得分:0)

一种或多或少直接的方法是以下代码,它源自 Pick 定理:

DECLARE @previousDayTransactionCount INT;
-- TODO: set this to MAX from gstl_daily_volume for current month


--- calculate per date total transaction fees
select
    Datee = CAST(C.transactionDate AS DATE),
    TotalSettlememtFee = SUM(C.settlementFees)
From
(
    select
        *
         -- each transaction counts as 1
        --,AuthFee = 1 * B.authFees
        --,SettlememtFee = 1 * settlementFees
    from
        (
            -- set a row number or transaction number per transaction which resets every month
            -- Then Add it here to current calculated rowNumber
            select
                rowNumber = @previousDayTransactionCount + (ROW_NUMBER() OVER(PARTITION BY DATEPART(MONTH, transactionDate), DATEPART(YEAR, transactionDate) ORDER BY transactionDate)),
                *
            from @transactionsTable tt
        ) A
        -- cross apply to calculate which range for each transaction
        CROSS APPLY
            (
                select
                    *
                From @rangeTable rtt
                    where A.rowNumber >= rtt.rangeStart
                        AND A.rowNumber < rtt.rangeEnd
            ) B
) C
-- group by date to get the per date fees
group by CAST(C.transactionDate AS DATE)