简体   繁体   English

最大素数算法优化

[英]Largest Prime Factor algorithm optimization

I'm trying to improve this interesting algorithm as much as I can. 我正在尝试尽可能多地改进这种有趣的算法。

For now, I have this: 现在,我有这个:

using System;

class Program
{

    static void Main()
    {
        ulong num, largest_pFact;
        uint i = 2;
        string strNum;

        Console.Write("Enter number: ");
        strNum = Console.ReadLine();
        num = ulong.Parse(strNum);
        largest_pFact = num;


        while (i < Math.Sqrt((double) largest_pFact))
        {
            if (i % 2 != 0 | i == 2) {
                if (largest_pFact % i == 0) 
                    largest_pFact /= i;
            }

            i++;
        }

        Console.WriteLine("Largest prime factor of {0} is: {1}", num, largest_pFact);
        Console.ReadLine();

    }
}

So any ideas? 有什么想法吗?

Thanks! 谢谢!

EDIT : I implemented Ben's algorithm, thanks eveyone for your help! 编辑 :我实现了本的算法,感谢eveyone的帮助!

I've got a faster algorithm here . 这里有一个更快的算法。

It eliminates the square root and handles repeated factors correctly. 它消除了平方根并正确处理了重复因素。

Optimizing further: 进一步优化:

static private ulong maxfactor (ulong n)
{
    unchecked
    {
        while (n > 3 && 0 == (n & 1)) n >>= 1;

        uint k = 3;
        ulong k2 = 9;
        ulong delta = 16;
        while (k2 <= n)
        {
            if (n % k == 0)
            {
                n /= k;
            }
            else
            {
                k += 2;
                if (k2 + delta < delta) return n;
                k2 += delta;
                delta += 8;
            }
        }
    }

    return n;
}

Here's a working demo: http://ideone.com/SIcIL 这是一个工作示例: http : //ideone.com/SIcIL

-Store Math.Sqrt((double) largest_pFact) in some variable, preferably a ulong. -将Math.Sqrt((double)maximum_pFact)存储在某个变量中,最好是ulong。 That avoids recalculating the function every pass through the loop, and integer comparison may be faster than floating-point comparisons. 这样可以避免在每次循环时都重新计算函数,并且整数比较可能比浮点比较更快。 You will need to change the comparison to a <= though. 不过,您需要将比较更改为<=。

-Avoid looping on even numbers at all. -避免完全循环偶数。 Just include a special case for i=2, and then start with i at 3, incrementing by 2 on each loop. 只需为i = 2添加一个特殊情况,然后从3的i开始,在每个循环上以2递增。 You can go even further by letting i=2,3 be special cases, and then only testing i = 6n+1 or 6n-1. 通过让i = 2,3是特例,然后仅测试i = 6n + 1或6n-1,您可以走得更远。

Well, first I would move the special case 2 out of the loop, there is no point in checking for that throughout the loop when it can be handled once. 好吧,首先,我将特殊情况2移出循环,当一次只能处理一次时,检查整个循环毫无意义。 If possible use the data type int rather than uint , as it's generally faster: 如果可能,请使用数据类型int而不是uint ,因为它通常更快:

if (largest_pFact % 2 == 0) {
  largest_pFact /= 2;
}
int i = 3;
while (i < Math.Sqrt((double) largest_pFact)) {
  if (i % 2 != 0) {
    if (largest_pFact % i == 0) {
      largest_pFact /= i;
    }
  }
  i++;
}

The square root calculation is relatively expensive, so that should also be done beforehand: 平方根计算相对昂贵,因此也应事先完成:

if (largest_pFact % 2 == 0) {
  largest_pFact /= 2;
}
int i = 3;
int sq = Math.Sqrt((double) largest_pFact);
while (i < sq) {
  if (i % 2 != 0) {
    if (largest_pFact % i == 0) {
      largest_pFact /= i;
    }
  }
  i++;
}

Then I would increment i in steps of two, to elliminate one modulo check: 然后,我将以两个为单位递增i ,以消除一个模检查:

if (largest_pFact % 2 == 0) {
  largest_pFact /= 2;
}
int i = 3;
int sq = Math.Sqrt((double) largest_pFact);
while (i < sq) {
  if (largest_pFact % i == 0) {
    largest_pFact /= i;
  }
  i += 2;
}

To work, I believe that you need a while instead of an if inside the loop, otherwise it will skip factors that are repeated: 要工作,我相信您需要一段while不是if循环,否则它将跳过重复的因素:

if (largest_pFact % 2 == 0) {
  largest_pFact /= 2;
}
int i = 3;
int sq = Math.Sqrt((double) largest_pFact);
while (i < sq) {
  while (largest_pFact % i == 0) {
    largest_pFact /= i;
  }
  i += 2;
}

For one thing, you don't need to run Math.Sqrt on every iteration. 一方面,您不需要每次迭代都运行Math.Sqrt

    int root = Math.Sqrt((double) largest_pFact);

    while (i < root)
    {
        if ((i % 2 != 0 | i == 2) && largest_pFact % i == 0) {
            largest_pFact /= i;
            root = Math.Sqrt((double) largest_pFact);
        }

        i++;
    }

I think: 我认为:

  • generate primes up to num /2 生成最多num / 2的素数
  • then check from largest to lowest if your num is divisible by the prime 然后从最大到最小检查num是否可以被素数整除

would be faster. 会更快。

edit num/2 NOT sqrt 编辑num / 2 NOT sqrt

It's always faster to look between sqrt(num) and 2 than it is to start at num/2. 在sqrt(num)和2之间查找总是比从num / 2开始更快。 Every factor pair (besides the square-root one) has one number that is less than sqrt(num). 每个因子对(除平方根之外)都具有一个小于sqrt(num)的数字。

Ex: For 15, int(sqrt(15))==3 15/3=5, so you found the "5" factor by starting your testing at 3 instead of 7. 例如:对于15,int(sqrt(15))== 3 15/3 = 5,因此您通过从3而不是7开始测试发现了“ 5”因子。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM