【问题标题】:Decomposition into prime factors [closed]分解成素数[关闭]
【发布时间】:2021-05-24 22:32:00
【问题描述】:

所以我遇到了一个我似乎无法解决的问题。我想显示它被提升到的因子和功率(基本上是素因子分解),我已经在 python 中完成了这个,但由于某种原因我无法在 C 中实现它,这就是我想出的

#include<stdio.h>
#include<math.h>

int main()
{
    int i = 2, p, c, n;
    scanf("%d", n);
    while (n > 9)
    {
        p = 0;
        c = 1;
        while (n % i == 0)
        {
            for (int d = 2; d <= i / 2 + 1; d++)
                if (i % d == 0 && i % 2 != 0)
                    c = 0;
            if (c == 1)
            {
                p = p + 1;
                n = n / i;
            }
            if (p != 0)
            {
                printf("%d %d", i, p);
                printf("\n");
            }
            i = i + 1;
        }
    }
    return 0;
}

【问题讨论】:

  • 具体来说,出了什么问题?您可能还希望在您的程序中修复您的缩进 - 其他人很难按照您拥有的不同寻常的风格来遵循代码。
  • 启用所有编译器警告并修复警告。对于scanf 行,您应该会收到类似main.c:7:10: warning: format ‘%d’ expects argument of type ‘int *’, but argument 2 has type ‘int’ [-Wformat=] 的警告。在调试器中运行你的程序,看看发生了什么。
  • @PaulHankin 进程以退出代码 -1073741819 (0xC0000005) 结束。这就是错误。另外我应该如何改变我的缩进?
  • @RaresAmza — 如果编译器打算对您的代码发出警告,请假设您的代码中存在错误并找出如何修复它。您可能需要阅读 GCC 手册。 GCC Warning Options 描述了选项及其发现的内容;现代版本的 GCC 会告诉您哪个警告选项触发了投诉。这在学习 C 的第一天可能会很困难,但它会在以后帮助你。
  • @RaresAmza 当您看到编译器警告或错误并且找不到足够的信息如何修复它们时,您可以在此处显示代码和消息并寻求帮助。

标签: c algorithm prime-factoring


【解决方案1】:

问题 #1(尽管这不是您的主要问题)是您在 scanf 调用中缺少一个指针:

scanf("%d", n);

应该是这样的

scanf("%d", &n);

(我的编译器马上就警告了我。不知道为什么你的没有。)

问题 #2 是 while (n &gt; 9) 完全错误。我想你想要while (n &gt; 1)

问题 #3 是 i = i + 1 步骤放错了位置。无论i 是否是一个因素,您都需要这样做,因此它需要位于最外层循环的末尾。

然后问题 #4 是开头的代码

for (int d = 2; d <= i / 2 + 1; d++)

看起来您正在尝试检查 i 是否是素数,尽管您这样做太晚了:您已经在 if 中,您可以在其中测试 i 是否是 @987654335 的一个因子@。此外,您没有适当的循环来计算in 的一个因素。

但事实证明,您实际上需要测试i 是否是素数,所以让我们暂时搁置素数测试步骤,看看会发生什么。

这是第一个固定版本:

#include <stdio.h>

int main()
{
    int i = 2, p, n;
    scanf("%d", &n);
    while (n > 1)
    {
        if (n % i == 0)           /* if i is a factor */
        {
            p = 0;  
            while (n % i == 0)    /* count how many times i is a factor */
                {
                n /= i;
                p++;
                }
        printf("%d %d\n", i, p);
        }

        i++;
    }
    return 0;
}

这行得通!它尝试了i 的所有可能值,这是非常低效的,但由于素数分解的特性,这没关系。它会按顺序尝试它们,因此它总是会首先清除所有较低的素因子,因此没有一个非素因子 i 会通过打印作为因子。

要执行我猜您想要执行的操作,我们必须重新排列代码。基本算法是:对于每一个i,如果是素数,看它分割了多少次运行的n

#include <stdio.h>

int main()
{
    int i = 2, p, c, n;
    scanf("%d", &n);
    while (n > 1)
    {
        /* see if i is prime */
        c = 1;
        for (int d = 2; d <= i / 2 + 1; d++)
            if (i % d == 0 && i % 2 != 0)
            {
                c = 0;
                break;
            }

        if (c == 1)                /* if i is prime */
        {
            p = 0;
            while (n % i == 0)     /* count how many times i is a factor */
            {
                p = p + 1;
                n = n / i;
            }

            if (p != 0)
                printf("%d %d\n", i, p);
        }
        i = i + 1;
    }
    return 0;
}

素数测试仍然很粗糙(if (i % d == 0 &amp;&amp; i % 2 != 0) 这条线很可疑),但它似乎有效。不过,我怀疑这仍然很浪费:如果您要生成所有可能的试验除数来分解 n,那么可能有比从头开始对每个 i 运行完整素数测试更好的方法。

一个流行的快捷方式是让i 遍历 2,3,5,7,9,11,13,...(即 2 加上所有奇数)。基于这个想法,我曾经写过一些代码,它使用更复杂的增量序列,因此它最终使用 2、3、5,然后是每个不是 3 或 5 倍数的奇数。我怀疑(但我没有测量过)浪费地使用一些非素试验除数 i 最终可能比肯定地确认每个试验除数都是严格素数更不浪费。

但是,如果您真的关心效率,您将不得不放弃这种盲目尝试所有试除数的明显但仍然相当暴力的技术,而转向更复杂的技术,例如 elliptic curve factorization。我们在这里做的是trial division,正如维基百科所说,它是“integer factorization 算法中最费力但最容易理解的”。

【讨论】:

  • 非常感谢!到目前为止,看起来我在这方面有点棒,但我会努力改进,感谢您指出我的错误,现在我知道我哪里做错了
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-20
  • 1970-01-01
  • 2020-12-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多