integer factorization
factor(divisor)
一個數字的「因數」,乘法分解而得的數字。通常有許多個。
0: 0 1 2 ... 5: 1 5 10: 1 2 5 10 1: 1 6: 1 2 3 6 11: 1 11 2: 1 2 7: 1 7 12: 1 2 3 4 6 12 3: 1 3 8: 1 2 4 8 13: 1 13 4: 1 2 4 9: 1 3 9 14: 1 2 7 14
prime factor
一個數字的「質因數」。又是因數、又是質數。
0: 2 3 5 ... 5: 5 10: 2 5 1: 1 6: 2 3 11: 11 2: 2 7: 7 12: 2 3 3: 3 8: 2 13: 13 4: 2 9: 3 14: 2 7
integer factorization
「整數分解」。一個正整數分解成質因數的連乘積。
5 = 5 10 = 2 × 5 1 = 1 6 = 2 × 3 11 = 11 2 = 2 7 = 7 12 = 2² × 3 3 = 3 8 = 2³ 13 = 13 4 = 2² 9 = 3² 14 = 2 × 7
正式名稱稱作「整數分解」,著眼於分解對象。中學課本譯作「質因數分解」,著眼於分解結果。
質因數分解屬於NP問題,但是目前還不確定它究竟是P問題或是NP-complete問題,相當特別。
fundamental theorem of arithmetic
「算術基本定理」。凡是正整數,都可以藉由質因數分解,成為一個獨一無二的式子。
n = 2n₁ × 3n₂ × 5n₃ × 7n₄ × 11n₅ × …
換句話說,不同的n對應不同的(n₁, n₂, …)。反方向亦然。
n ←—→ (n₁, n₂, n₃, n₄, n₅, …)
根據算術基本定理,凡是牽扯到乘法、除法、因數、倍數的數學運算,可以變成比較簡單的運算。
分解前 | 分解後 n | (n₁, n₂, …) m | (m₁, m₂, …) -------------------------------------------------- 乘除法 | 加減法 n × m | (n₁ + m₁, n₂ + m₂, …) n ÷ m | (n₁ - m₁, n₂ - m₂, …) | 整除 | 大於等於 n % m = 0 | (n₁, n₂, …) ≥ (m₁, m₂, …) m | n | n₁≥m₁ and n₂≥m₂ and … | 最大公因數 | 最小值 gcd(n, m) | (min(n₁, m₁), min(n₂, m₂), …) | 最小公倍數 | 最大值 lcm(n, m) | (max(n₁, m₁), max(n₂, m₂), …) | 互質 | 對應項必須有零 n ⊥ m | min(n₁, m₁) = 0 and min(n₂, m₂) = 0 and … | n₁×m₁ = 0 and n₂×m₂ = 0 and …
算術基本定理闡述了另一種世界觀,把數字看作是質數的結合。質數的英文prime有著「原始就有」的意思,便是指質數是所有數字的根本。
UVa 11889
integer factorization: trial division algorithm
trial division algorithm
把所有可能的因數拿來試除。由小到大試除,即時消滅因數,因此每次整除的是質因數。時間複雜度O(n)。
n不是質數的情況,遠小於O(n)。精確的寫法是O(max(pₖ) + sum(eₖ))。pₖ和eₖ來自質因數分解n = p₁e₁ × p₂e₂ × ...。
平均時間複雜度,似乎可以精確用n表示,但是我沒有研究。讀者可以逕行上網搜尋「最大質因數分布」、「質因數數量分布」。
因數成雙成對(平方根跟自己一對),窮舉一半足矣。乘法分解的一半:平方根。時間複雜度降為O(sqrt(n))。
精確的寫法是O(sqrt(max(pₖ)) + sum(eₖ))。
預先處理質因數2,然後每次跳二,節省一半時間。
wheel factorization可以節省更多時間。
UVa 516 583 10179 10290 10329 10392 10622 10780 10791 10879
integer factorization: Pollard's ρ algorithm
亂數產生器
此演算法可以找到n的其中一個因數。
使用一個簡單的亂數產生器f(aᵢ₊₁) = aᵢ² + c (mod n),嘗試各種a₀與c,製造所有可能的因數,一一試除即可。
以此亂數產生器公式,依序枚舉a₀ a₁ a₂ …,模n的情況下,最終必定循環。圖示習慣畫成一個ρ的形狀,演算法因此而得名。
小寫希臘字母ρ,唸作/ro/,可以寫作rho。
運用最大公因數找到因數
因為亂數產生器製造的數字a,a恰是n的因數的機會較小,而a與n有共同因數的機會較大,所以改用d = gcd(a, n)來找到n的因數d。最大公因數有著極快的演算法,對執行時間影響不大。
偵測循環
亂數產生器最終必會出現重覆數字,產生循環。一旦遇到循環,立刻結束枚舉,不再進行重覆運算。
另外,此演算法改用abs(aₓ - a),用數字的差值製造所有可能的因數。我不知道如此做的原因。
原論文採用「Floyd's algorithm」偵測循環。
亦可採用「Brent's algorithm」偵測循環,效率較佳。
讀者可以思考一下這些問題
一、為何亂數產生器不採用f(aᵢ₊₁) = aᵢ + c (mod n)這條更加簡單的式子?
二、為何a₀至少要是+2?(經過實測,a₀最好是+2。)
三、為何c最好不是0和-2?試試看將亂數產生器公式,代入到x和y之中,計算一下x-y,然後計算一下gcd(abs(x-y), n)。
四、為何x等於y的時候,就要馬上結束迴圈呢?
五、如果略去abs(),改成gcd(x-y, n),對結果有影響嗎?
質因數分解
似乎只要嘗試各種c,就一定可以窮舉出所有可能的因數。我不知道原因。
UVa 11476 11466
integer factorization: quadratic sieve algorithm
Fermat's factorization method
一個數字n,分解成兩個數x y的乘積。
運用平方差公式,令n = a² - b² = (a+b) (a-b) = x y。尋找剛好相差n的兩個平方數a²與b²,就能分解n。
實作程式碼時,窮舉整數a,然後推導出b = sqrt(a² - n),判斷b是不是整數。
GCD-free basis
GCD-free basis
請見專著《Algorithmic Number Theory》。
質因數分解:一個數字分解成質數相乘。時間複雜度類別不明。
互質因數分解:每個數字分解成互質數字相乘,盡量使用最大公因數。時間複雜度是多項式時間。