約数の個数
自然数の約数(divisor)は、素因数分解されていると簡単に求まります。まず、8の約数は、23だから、2をいくつ選ぶかで決まります。すなわち、0〜3個のうちどれかを選ぶことになります。
1 = 20
2 = 21
4 = 22
8 = 23
ですから、8の約数の個数は4です。
次に24を考えましょう。24 = 23 • 31ですが、約数を列挙すると次のようになります。
1 = 20 • 30
2 = 21 • 30
4 = 22 • 30
8 = 23 • 30
3 = 20 • 31
6 = 21 • 31
12 = 22 • 31
24 = 23 • 31
24は素因数に2と3を持つので、約数は2と3を独立にいくつ選ぶかで決まります。2は4通り、3は2通り選べるので、8通り選べる、すなわち約数の個数は8となります。
一般に、
n = p1e1 … pmem
とすると、nの約数の個数は、
(e1 + 1) … (em + 1)
となります。
# factorizeは下参照
def num_divisors(n):
return reduce(lambda x, y: x * (y[1] + 1), factorize(n), 1)print num_divisors(24)
約数の総和
まず、8の約数の総和は、
1 + 2 + 22 + 23 = 24 - 1
となります。
次に、24の約数の総和は、3で割り切れるかどうかで括って、
(1 + 2 + 22 + 23) + 3(1 + 2 + 22 + 23) = (24 - 1)(32 - 1) / 2
一般に、
n = p1e1 … pmem
とすると、nの約数の個数は、
(p1e1+1 - 1) / (p1 - 1) … (pmem+1 - 1) / (pm - 1)
となります。
def sum_divisors(n):
def f(x, y): return x * (y[0] ** (y[1] + 1) - 1) / (y[0] - 1)
return reduce(f, factorize(n), 1)print sum_divisors(24)
約数を列挙する
これも同様です。24ならまず、3から1と3が出ます。8から1,2,4,8が出るので、そこに1と3をそれぞれ掛けます。
def calc_exp(n, p):
e = 0
while n % p == 0:
e += 1
n /= p
return e, ndef gen_prime_candidates():
yield 2
n = 3
while True:
yield n
n += 2def factorize(n):
f = ()
for m in gen_prime_candidates():
if m * m > n:
break
e, n = calc_exp(n, m)
if e:
f = f + ( (m, e), )
if n != 1:
f = f + ( (n, 1), )
return fdef gen_divisors(f, k = 0):
if k == len(f):
yield 1
else:
p, e = f[k]
for d in gen_divisors(f, k + 1):
for e1 in range(e + 1):
yield p ** e1 * df = factorize(24)
for d in gen_divisors(f):
print d