簡単に言えば、私の英語はひどいので;-)
Forall n >= 1, C(n) = n/2 if n even,
3*n + 1 if n odd
一度に複数の連続した反復を計算することができます。
k0
ビットで終わる数値の k 番目の反復:
C^k(a*2^k) = a
1
kビットで終わる数値の (2k) 番目の反復:
C^(2k)(a*2^k + 2^k - 1) = a*3^k + 3^k - 1 = (a + 1)*3^k - 1
参照。ウィキペディアの記事の数式(フランス語) ; 私のウェブサイト(フランス語) と私の Python パッケージDSPythonのモジュールtnp1も参照してください。
次のコードを、Niklas B によって説明されたメモ化の手法と組み合わせます。
#!/usr/bin/env python
# -*- coding: latin-1 -*-
from __future__ import division # Python 3 style in Python 2
from __future__ import print_function # Python 3 style in Python 2
def C(n):
"""Pre: n: int >= 1
Result: int >= 1"""
return (n//2 if n%2 == 0
else n*3 + 1)
def Ck(n, k):
"""Pre: n: int >= 1
k: int >= 0
Result: int >= 1"""
while k > 0:
while (n%2 == 0) and k: # n even
n //= 2
k -= 1
if (n == 1) and k:
n = 4
k -= 1
else:
nb = 0
while (n > 1) and n%2 and (k > 1): # n odd != 1
n //= 2
nb += 1
k -= 2
if n%2 and (k == 1):
n = (n + 1)*(3**(nb + 1)) - 2
k -= 1
elif nb:
n = (n + 1)*(3**nb) - 1
return n
def C_length(n):
"""Pre: n: int >= 1
Result: int >= 1"""
l = 1
while n > 1:
while (n > 1) and (n%2 == 0): # n even
n //= 2
l += 1
nb = 0
while (n > 1) and n%2: # n odd != 1
n //= 2
nb += 1
l += 2
if nb:
n = (n + 1)*(3**nb) - 1
return l
if __name__ == '__main__':
for n in range(1, 51):
print(n, ': length =', C_length(n))