数 n (たとえば 300) を素因数の積として表すには、まず最小の素数 p (2) から始め、n が割り切れる限り繰り返し n を p で割ります (300 / 2 = 150, 150 / 2 = 75)。
その後、p を 1 ずつ増やして (p = 3)、再び n が割り切れるかを試します。割り切れるならば、可能な限り繰り返し n を割り続けます (75 / 3 = 25)。
次に p を再度 1 ずつ増やすと (p = 4)、もう二度と n は 4 で割り切れません。というのも、すでに 2 で割り切れるだけ割り尽くしているので、4 や 6、8 のように 2 の倍数になっている数ではこれ以上割り切ることができないためです。このアルゴリズムは最小の数から大きい数へと順に進むので、最終的に残った数については、すでに素数のみで割り尽くしていることが保証されます。
次のステップでは再び 1 だけ増やし (p = 5)、n が割り切れるかを調べます。今回の場合、75 / 5 = 5、さらに 5 / 5 = 1 となります。こうして割れるだけ割ったら、次へ進みます。そして p が よりも大きくなった時点でループを終えます。もしその時点で n が 1 より大きければ、残っている n 自体が素数として採用できます。
以上の手順で例の 300 は という形に表せます。
n = ... # n を素因数の積として表す
p, divisors, powers = 1, [], [] # prime factor, divisors, and their exponents
while p * p <= n: # p <= sqrt(n) の間繰り返す
p += 1 # 反復ごとに p を 1 ずつ増やす
if n % p != 0: # n が p で割り切れないなら何もしない
continue
divisors.append(p) # n % p == 0 => 素因数として p を追加
powers.append(0) # 指数を 0 から始める
while n % p == 0: # 割り切れるだけ割り、
n //= p
powers[-1] += 1 # 割るたびに指数を 1 ずつ増加させる
if n > 1: # p > sqrt(n) の時点で n が 1 より大きいなら、
divisors.append(n) # n 自体が素数となるので追加
powers.append(1) # 指数を 1 として追加
print(list(zip(divisors, powers))) # 因数とその指数のペアを出力
各反復で、もし割り切れるなら対象の数を素因数で割り、そのたびに指数を 1 ずつ増やしていきます。
それでは、いくつかの数でアルゴリズムをシミュレーションしてみましょう。
n = 24
p = 2, n = 24 (ループの最初に p を 1 から 2 へ増やした状態で始める)
n % 2 == 0 ⇒ divisors = [2], powers = [0]n //= 2 ⇒ n = 12, powers = [1]
n //= 2 ⇒ n = 6, powers = [2]n //= 2 ⇒ n = 3, powers = [3]
p = 3, n = 3 ⇒ p * p = 9 は 2 より大きいので while ループを終了
n > 1 ⇒ divisors = [2, 3], powers = [3, 1]
n = 75
p = 2, n = 75
p = 3, n = 75n % 3 == 0 ⇒ divisors = [3], powers = [0]n //= 3 ⇒ n = 25, powers = [1]
p = 4, n = 25
p = 5, n = 25n % 5 == 0 ⇒ divisors = [3, 5], powers = [1, 0]n //= 5 ⇒ n = 5, powers = [1, 1]n //= 5 ⇒ n = 1, powers = [1, 2]
p * p > n ⇒ ループ終了 ⇒ divisors = [3, 5], powers = [1, 2]
n = 84
p = 2, n = 84n % 2 == 0 ⇒ divisors = [2], powers = [0]n //= 2 ⇒ n = 42, powers = [1]n //= 2 ⇒ n = 21, powers = [2]
p = 3, n = 21n % 3 == 0 ⇒ divisors = [2, 3], powers = [2, 0]n //= 3 ⇒ n = 7, powers = [2, 1]