【问题标题】:How do I prime factorize large numbers?如何对大数进行质因数分解?
【发布时间】:2020-03-30 11:21:16
【问题描述】:

我正在尝试解决Project Euler third question,但是当我尝试使用大数字时,我的代码可以完美地处理小数字,但它没有给我任何答案。

#include<iostream>

using std :: cout;
using std :: cin;
using std :: endl;

int main()
{
   long long int a = 0, bigPrime = 0, smallPrime = 2, prime = 0;
   cout << "Please enter a number...!" << endl;
   cin >> a;

   for(long long int i = 2 ; i < a ; i++)
   {
      for(long long int c = 2 ; c < i ; c++)
      {
         if(i % c != 0)
         {
            prime = i;
         }
         else
         {
            prime = 0;
            break;
         }
      }
      if(prime > 0 )
      {
         if(a % prime == 0)
         {
            bigPrime = prime;
         }
      }

  }


  cout << "The biggest prime is = " << bigPrime << endl;
  return 0;

}

那是我的错误代码 :) 我正在使用 ubuntu linux 和 g++ 我的代码有什么问题,我该如何改进它?

【问题讨论】:

  • 你的small numbersbig numbers在什么范围内撒谎?
  • 什么是无效的数字示例?我敢打赌 > (2^127)-1
  • 例如 600851475143 这个数字不起作用,但如果我使用像 1000 或 23613 这样的数字,它可以完美地工作
  • 在 Euler 案例中,您的外循环迭代超过六千亿次,而大多数内循环也是数十亿次。欧拉问题通常需要您在尝试解决方案之前使用数学,并且非常罕见地采用蛮横的方法。
  • 我再次查看了我的程序,我发现我的代码可能可以工作,但它就像 molbdnilo 所说的那样太慢了(如果有语法错误,抱歉)

标签: c++ algorithm math prime-factoring


【解决方案1】:

您可以使用一个简单的技巧来改进您的程序:

每次找到除数 d 时,将您的数字除以 d

这意味着对于找到的每个除数,您的数字都会变小,从而使剩余部分更容易因式分解。

作为奖励,这意味着您不必非常小心只使用素数作为除数。每次找到一个除数,它就是当前数的最小除数,既然是最小除数,它一定是素数。这样可以节省整个循环级别。

因子是按从小到大的顺序提取的,所以最终你拥有的是最高的素因子——这个挑战的答案。

这不是一个快速的算法,但是 600851475143 不是一个很大的数字,这个算法不会有问题。

例如 (on ideone):

for (long long int d = 2; d * d <= a; d++) {
    if (a % d == 0) {
        a /= d;
        d--; // this is to handle repeated factors
    }
}

我也使用了旧的d * d &lt;= a 技巧,但你甚至不需要它。如果最高因素很高,这会有所帮助,而在本例中并非如此。

【讨论】:

  • 好答案。我可能会用 while 语句替换 if 语句以避免 d-- 部分
  • 感谢您的回答,这正是我想要的(我是新来的,多么有用的平台:))
  • 我会考虑在循环之前测试2 是否是一个特殊情况,然后在d = 3 开始测试并在每个步骤中添加2。这个简单的调整将(几乎)将检查的值数量减半。还有一些相当有效的方法来计算“整数平方根”(即,当乘以自身时超过a 的最小整数) - 进行一次计算将意味着测试循环条件的工作更少,特别是对于较大的值。
【解决方案2】:

但是problem 声明您只需要找到 600851475143 的最大素数,对吗?为什么不直接从 sqrt(600851475143) 迭代到 2 并返回第一个素数?

bool isPrime(uint64_t num)
{
  bool result = true;
  for(uint64_t i = 2; i < std::sqrt(num); ++i)
  {
    if(num % i == 0)
    {
      result = false;
      break;
    }
  }
  return result;
}

int main()
{
  uint64_t num = 600851475143;
  uint64_t i = std::sqrt(num);
  while (i > 1)
  {
    i--;
    if (num%i != 0) continue;
    if (isPrime(i))
    {
      break;
    }
  }
  std::cout << i << std::endl;
  return 0;
}

当然可以做得更快,但在我的机器上需要 10ms,所以我想这并不可怕。

【讨论】:

  • 谢谢伙计,现在我对 uint64_t decleration 没有任何了解,但我会用谷歌搜索它
【解决方案3】:
#include <iostream>

using namespace std;

typedef long long ulong;

int main()
{
ulong num = 600851475143;
ulong div = num;
ulong p = 0;

ulong i = 2;
while (i * i <= div)
{
    if (div % i == 0)
    {
        div /= i;
        p = i;
    }
    else {
        i++;
    }
}

if (div > p) 
{ 
    p = div;
}

cout << p << endl;

return 0;
}

【讨论】:

  • while 循环的内部可以替换为 while(div % i == 0) div /= i; ++i
  • 谢谢回答,对我真的很有帮助
猜你喜欢
  • 1970-01-01
  • 2010-11-27
  • 1970-01-01
  • 2015-06-07
  • 2019-04-26
  • 2013-04-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多