如何提高c ++代码的效率(找到最大的素数因子)?

时间:2015-09-07 04:22:13

标签: c++ algorithm mathematical-optimization

如何提高此代码的效率?

假设您必须处理非常大的投入。

‪#‎include‬ <iostream>
using namespace std;
int main()
{   //This program finds out the largest prime factor of given input
    long int n,big=1;
    cin>>n;
    for (long int i=2;i<n;i=i+2)
    {
        if (n%i==0)
           big=i;
    }
    cout<<big;
    return 0;
}

1 个答案:

答案 0 :(得分:3)

首先,我认为你所拥有的代码无论如何都会给你最大的 prime 因子,它只是给你最大的因素,无论是素数还是复合( 1)

如果你是在最大的素数因子之后(或者如果没有则为零),可以通过重复的整数除法找到它,类似于UNIX factor程序的许多实现的工作方式,以及以下几行:

def largestPrimeFactor(n):
    if n < 2: return 0            # Special case

    denom = 2                     # Check every denominator
    big = 0
    while denom * denom <= n:     # Beyond sqrt, no factors exist
        if n % denom == 0:        # Check factor, then divide
            big = denom
            n = n / denom
        else:
            denom = denom + 1     # Or advance to next number

    if n > big:                   # What's left may be bigger
        big = n

    return big

如果您希望甚至更多效率,您可以更改每次循环修改分母的方式。一旦你检查了两个,每个其他素数必须是奇数,这样你就可以避免重新检查偶数,有效地减少了所花费的时间:

def largestPrimeFactor(n):
    if n < 2: return 0            # Special case

    while n % 2 == 0: n = n / 2   # Check and discard twos
    if n == 1: return 2           # Return if it was ALL twos

    denom = 3                     # Check every denominator
    big = 0
    while denom * denom <= n:     # Beyond sqrt, no factors exist
        if n % denom == 0:        # Check factor, then divide
            big = denom
            n = n / denom
        else:
            denom = denom + 2     # Or advance to next odd number

    if n > big:                   # What's left may be bigger
        big = n

    return big

还有另一种跳过更多复合材料的方法,它依赖于数学上的事实,除了23之外,每个其他素数的形式都是6n±1 (2)功能

某些复合材料也有此表单,例如2533,但您可以在此处使用的低效率。

虽然使用奇数的变化比最初的努力减少了50%,但是这个变为削减了奇数变体的另外33%:

def largestPrimeFactor(n):
    if n < 2: return 0            # Special case

    while n % 2 == 0: n = n / 2   # Check and discard twos
    if n == 1: return 2           # Return if it was ALL twos

    while n % 3 == 0: n = n / 3   # Check and discard threes
    if n == 1: return 3           # Return if it was ALL threes

    denom = 5                     # Check every denominator
    adder = 2                     # Initial value to add
    big = 0
    while denom * denom <= n:     # Beyond sqrt, no factors exist
        if n % denom == 0:        # Check factor, then divide
            big = denom
            n = n / denom
        else:
            denom = denom + adder # Or advance to next denominator,
            adder = 6 - adder     #    alternating +2, +4

    if n > big:                   # What's left may be bigger
        big = n

    return big

这里的诀窍是从五点开始,交替地在四点加两点:

                      vv         vv        (false positives)
5  7 11 13  17 19  23 25  29 31  35 37  41 ...
    9     15     21     27     33     39   (6n+3, n>0)

你可以看到它跳过每三个奇数(9, 15, 21, 27, ...),因为它是三的倍数,这是进一步减少33%的地方。在这种情况下,您还可以看到素数的误报(2533,但会发生更多)。

(1)您的原始标题需​​要最大的偶数素因子和最有效的查找代码,这将是非常快速的:

if (n % 2 == 0)
    cout << 2 << '\n';
else
    cout << "None exists\n";

(因为只有一个甚至素数)。但是,我怀疑这是你真正想要的。

(2)将任何非负数除以6。如果余数是0,2或4,则它是偶数,因此非素数(2是这里的特例):

6n + 0 = 2(3n + 0), an even number.
6n + 2 = 2(3n + 1), an even number.
6n + 4 = 2(3n + 2), an even number.

如果余数为3,那么它可以被3整除,因此非素数(3是这里的特例):

6n + 3 = 3(2n + 1), a multiple of three.

只剩下剩余的1和5,这些数字都是6n±1的形式。因此,处理23作为特殊情况,从5开始,然后交替添加24,您可以保证所有素数(和很少复合材料)将被捕获。