您正在檢查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