【问题标题】:Why is my GCD program in C not running?为什么我的 C 语言 GCD 程序没有运行?
【发布时间】:2016-05-07 20:43:49
【问题描述】:

我正在尝试使用 C 中的欧几里德算法(递归)找到两个数字的 GCD,我确实知道它在数学上并不完全完美,因为它忽略了负数条件,但我只希望这个适用于正数暂时。

#include <stdio.h>

int gcd(int m, int n);

int main() {
    return gcd(60, 24);
}

int gcd(int m, int n) {
    if (m < n) {
        //swapping both a and b
        m = m + n;
        n = m - n;
        m = m - n;
    }
    if (m == n) {
        return m;
    } else {
        return gcd(n, m % n);   
    }
}

【问题讨论】:

  • 你的终止条件不够宽泛;并不总是最终 m==n 在(实际)算法结束时成立。示例帮助(例如 gcd(4, 2) -> gcd(2, 0)...)
  • 是的,这是真的,但是对于所有正数,它最终都归零,除了我想知道的要点是为什么这个程序不能为 gcd(60,24) 运行如果我们遵循欧几里德的算法,我很确定它会归零。
  • 嗯,(60, 24) -> (24, 12) -> (12, 0)。你的算法继续。这很糟糕......
  • 大多数情况最终会到达(m, 0)作为最终迭代。此时,它需要返回m。相反,它将尝试评估m % 0,这当然会导致错误。将m == n 条件更改为n == 0 以修复它。
  • 感谢 Pachelbel 和 @Tom Karzes 非常感谢。尽管我保留了 m==n 条件来停止让程序进入计算,因为很明显如果 m==n 时 gcd 将是 m。所以我将只添加另一个检查 if(n==0) 而不是仅仅替换 m==n if 语句。谢谢。 :D

标签: c algorithm function recursion greatest-common-divisor


【解决方案1】:

递归 GCD 的代码如下所示

int gcd(int m, int n)
{
    if (n==0)
        return m;

    return gcd(n, m % n);
}

不需要交换参数,因为这将由递归处理。例如,考虑gcd(24, 60)。在这种情况下n=60m % n = 24%60 = 24。所以递归调用是gcd(60,24),自动交换参数。

【讨论】:

  • 是的,这比被接受的解决方案更清洁、更高效。
  • 只有找到 UB 的案例是 gcd(INT_MIN,-1), gcd(-1, INT_MIN)gcd() 真正用于无符号参数。
【解决方案2】:

gcd(60, 24) -> gcd(24, 12) -> gcd(12, 0).

这意味着您需要添加支票。

if ( n == 0 )
{
   return m;
}

if ( m%n == 0 )
{
   return n;
}

您还可以通过对函数的另一次调用以及在调用中交换的值来删除变量交换代码。

int gcd(int m, int n) {

   if (m < n) {
      return gcd(n, m);
   }

   if (m%n == 0) {
      return n;
   } else {
      return gcd(n, m % n);   
   }
}

【讨论】:

  • 这应该替换m == n 检查。即,这不是附加检查,而是更正检查。
  • 此解决方案每次迭代执行两个% 操作,当只需要一个时(除非编译器通用 subs 操作)。一个更好的解决方案是简单地检查零操作数。更不用说如果操作数为零,这个解决方案就会失败(没有好的 gcd 算法会这样做)。
  • @TomKarzes,我玩弄了使用第一个条件的想法 - if ( n == 0 ) return m;。我犹豫了,因为我不确定 gcd 在非零数和零之间的数学定义是什么。当来自main 的呼叫是gcd(20, 0) 时会发生什么。我意识到调用会使程序崩溃。尽管如此,这个问题仍然存在。
  • 看看user3386109发布的解决方案。它更简单、更高效。
  • @TomKarzes,它肯定更干净。我无法确定它是否更有效。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多