challenge コラッツ・角谷の問題

任意の数nを与えたときに
・nが偶数ならば2で割る (n=n/2)
・nが奇数ならば3倍して1を足す (n = 3*n+1)
を繰り返すと、いづれは1になる。というものがあります。

数値計算の上ではかなりの数まで成り立つことが知られています。
(すべての数について成り立つかは不明)
参考リンク先参照

ある任意の数nがコラッツ・角谷の問題で1になるまでのステップ数をf(n)とします。
1~2^20までの数でf(n)を求めて、f(n)が最大になるときのnとf(n)を表示してください。

たとえばn=9だと次のような数列をたどって、19ステップで1になります。
9->28->14->7->22->11->34->17->52->26->13->40->20->10->5->16->8->4->2->1
つまりf(9)=19です。

また、最大を求めた際の実行時間と環境を書いてください。

Posted feedbacks - OCaml

OCamlは64bit整数を扱いだすと色々とオーバーヘッドが大きくなるので、なるべくintで
計算を行うようにして、あるところでint64に切り替えるようにしてます。
また、キャッシュもint64モードでは持たないようにして、ハッシュではなく配列で
アクセスの高速化を図っています。

PentiumM 1.7GHzで0.2秒強です。

 % time ./dk120
 f(837799)=524
 
 real    0m0.227s
 user    0m0.220s
 sys     0m0.007s
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
open Int64

let maxN       = 1048576
let cacheN     = maxN
let cacheN64   = Int64.of_int (2 * cacheN)

let memo = Array.create (cacheN+1) 0

let rec colatz31 = function
    | 1 -> 0
    | n ->
        if memo.(n) <> 0 then memo.(n) else (
            let c = 1 +
                if n land 1 = 0 then colatz31 (n lsr 1)
                else (
                    let t = n * 3 + 1 in
                    if t <= cacheN then colatz31 t
                                   else colatz64 (of_int t)) in
            let _ = memo.(n) <- c in c)

and colatz64 n =
    let t = to_int n in
    if (t land 1) = 0 then (
        if n <= cacheN64 then 1 + colatz31 (t lsr 1)
                         else 1 + colatz64 (shift_right_logical n 1)
    ) else 1 + colatz64 (succ(mul n 3L))

let rec loop max1 max2 = function
    | n when n > maxN -> max1, max2
    | n -> let max = colatz31 n in
        if max > max2 then loop n max (n+1) else loop max1 max2 (n+1)

let _ =
    let a,b = loop 0 0 1 in
    Printf.printf "f(%d)=%d\n" a b

Index

Feed

Other

Link

Pathtraq

loading...