您正在检查25 = 3,814,697,265,625数字是否为总数。这是很多主要测试,并且总是需要很长时间。即使在最好的情况下(对于性能来说),当所有数组条目(在m
中)都是0(不必介意测试认为0是一个素数),以便试验分割循环从不运行,它将需要数小时才能运行。当m
的所有条目均为正数时,代码将持续数百或数千年,此后每个数字将被试用除以50,000,000以上的数字。
望着总理检查,
check_prime = 1;
for (y = 2; y <= num/2; y++)
{
if (num % y == 0)
check_prime = 0;
}
第一刺目的效率低下是一个除数已经发现的num
的compositeness成立后也继续循环。 一旦知道结果就立即打开循环。
check_prime = 1;
for (y = 2; y <= num/2; y++)
{
if (num % y == 0)
{
check_prime = 0;
break;
}
}
在不幸的情况下,所有的号码,你的测试是黄金,这不会改变任何事情,但如果所有(或几乎所有的近足够大的值)的数字是复合材料,它会将运行时间减少至少5000倍。
接下来的事情是,你分为num/2
。这没有必要。为什么你停在num/2
,而不是在num - 1
?那么,因为你发现num
的最大合适除数不能大于num/2
,因为如果(num >) k > num/2
,那么2*k > num
和num
不是k
的倍数。
这很好,不是每个人都能看到的。
但你可以进一步追求这一思路。如果num/2
是num
的除数,则表示num = 2*(num/2)
(使用整数除法,但num = 3
除外)。但是num
是偶数,并且它的合成度已经由除数2确定了,所以如果成功的话,num/2
的分割将不会被尝试。
那么需要考虑的最大除数的下一个可能候选项是什么? num/3
当然。但如果这是num
的除数,那么num = 3*(num/3)
(除非num < 9
)以及除以3已经解决了这个问题。
往前走,如果k < √num
和num/k
为num
,然后num = k*(num/k)
除数,我们看到num
具有较小的除数,即k
(甚至可能是更小的)。
所以num
的最小非平凡除数小于或等于√num
。因此,循环仅需要运行y <= √num
或y*y <= num
。如果在该范围内未找到除数,则num
是首要的。
现在的问题是是否循环
for(y = 2; y*y <= num; ++y)
或
root = floor(sqrt(num));
for(y = 2; y <= root; ++y)
第一需要一次乘法用于每次迭代循环条件,循环外的平方根中的第二个计算。
哪个更快?
这取决于num
的平均大小以及许多是否为素数(更准确地说,取决于最小素数除数的平均大小)。计算平方根需要比乘法长得多,为了补偿成本,循环必须运行许多迭代(平均) - 无论“多”意味着超过20,超过100或超过1000,取决于。由于num
大于10^8
,这可能是这种情况,可能计算平方根是更好的选择。
现在我们已经限定的审判庭循环迭代的次数√num
是否num
是复合材料或素数,减少了至少5000因数运行时间(假设所有m[index] > 0
,所以总是num >= 10^8
),而不管测试的数字中有多少个素数。如果大多数值为num
需要的是具有小质因子的复合材料,则缩小因子要大得多,通常运行时间几乎完全用于测试质数。
通过减少除数的候选数可以获得进一步的改进。如果num
可以被4,6,8 ......整除,那么它也可以被2整除,所以即使y > 2
,num % y
也不会产生0。这意味着所有这些部门都是多余的。通过特殊的外壳2和增量在2个步骤除数候选人,
if (num % 2 == 0)
{
check_prime = 0;
} else {
root = floor(sqrt(num));
for(y = 3; y <= root; y += 2)
{
if (num % y == 0)
{
check_prime = 0;
break;
}
}
}
分割数来执行和运行时间大致减半(假设已经够糟糕的情况下,对偶数的工作是可以忽略不计)。
现在,每当y
是3(除3本身)的倍数,num % y
将只当num
不是3的倍数来计算,所以这些划分也是多余的。你也可以通过特殊套管3消除它们,并让y
只能穿过不能被3整除的奇数(从y = 5
开始,交替增加2和4)。这大约剩余工作的三分之一(如果存在足够的不良情况)。
继续是消除过程,我们只需要通过素数划分num
不超过√num
发现无论是黄金还是不是。
所以平时它是要找到不超过你会检查最大num
的平方根的素数是一个好主意,将其存储在一个数组和循环
root = floor(sqrt(num));
for(k = 0, y = primes[0]; k < prime_count && (y = primes[k]) <= root; ++k)
{
if (num % y == 0)
{
check_prime = 0;
break;
}
}
除非最大值num
能例如,如果你总是拥有num < 2^31
,那么你应该在比特筛中找到该限制的素数,这样你就可以查找num
是否在恒定时间内是质数(一个2^31位需要256 MB,如果你只有奇数的标志[需要特殊的外壳来检查num
是否是偶数],你只需要128 MB来检查恒定时间的数字< 2^31
的原始性,可以进一步减少筛子所需的空间)。
到目前为止对于主要测试本身。
如果m
数组包含由2或5整除数,它可能是值得的重新排序的循环,具有用于i
循环中的最外层,和由2或5跳过内部循环,如果m[i]
整除 - 所有在添加之前其他数字乘以10的幂,因此num
将是2的倍数。 5而不是素数。
但是,尽管如此,运行代码仍需要很长时间。九个嵌套循环讨厌错误的设计。
你试图做什么?也许我们可以帮助找到正确的设计。
For-mat-ting ... –
您正在检查25^8个不同的数字是否与天真的因素搜索素数相符。这**肯定需要很长时间。 – Hbcdev
25^8素数检查永远不会过快,但是通过将'for(y = 2; y <= num/2; y ++){...}'更改为'if(num> 2 && (y = 3; y * y <= num && check_prime; y + = 2){...}' – stefan