Collatzの予想

Collatz(コラッツ)の予想は,角谷(かくたに)予想ともいいます。次のプログラムが必ず停止するという予想です。

class Collatz {
    public static void main(String[] args) {
        int n = Integer.parseInt(args[0]);
        while (n > 1) {
            if (n % 2 == 0) n = n / 2;
            else n = 3 * n + 1;
            System.out.println(n);
        }
    }
}

これを Collatz.java として保存し,

javac Collatz.java

でコンパイルします。

java Collatz 30

などのように適当な数を与えて実験してみましょう。

java Collatz 30
15
46
23
70
35
106
53
160
80
40
20
10
5
16
8
4
2
1

どんな数から始めても,必ず1になりそうです。

遊んでいるうちに,変な現象に出会うかもしれません。

java Collatz 113383
340150
170075
510226
255113
765340
382670
191335
574006
287003
861010
430505
1291516
645758
322879
968638
484319
1452958
726479
2179438
1089719
3269158
1634579
4903738
2451869
7355608
3677804
1838902
919451
2758354
1379177
4137532
2068766
1034383
3103150
1551575
4654726
2327363
6982090
3491045
10473136
5236568
2618284
1309142
654571
1963714
981857
2945572
1472786
736393
2209180
1104590
552295
1656886
828443
2485330
1242665
3727996
1863998
931999
2795998
1397999
4193998
2096999
6290998
3145499
9436498
4718249
14154748
7077374
3538687
10616062
5308031
15924094
7962047
23886142
11943071
35829214
17914607
53743822
26871911
80615734
40307867
120923602
60461801
181385404
90692702
45346351
136039054
68019527
204058582
102029291
306087874
153043937
459131812
229565906
114782953
344348860
172174430
86087215
258261646
129130823
387392470
193696235
581088706
290544353
871633060
435816530
217908265
653724796
326862398
163431199
490293598
245146799
735440398
367720199
1103160598
551580299
1654740898
827370449
-1812855948

あれあれ,マイナスになってしまいました。どうしてでしょう?

テストのために次のようなプログラムを作ってみました。

class Test {
    public static void main(String[] args) {
        int n = Integer.parseInt(args[0]);
        for (int i = 0; i < 10; i++)
            System.out.println(n + i);
    }
}

これは入力した数から始まる10個の数を出力するものです。2147483643あたりから始めてみましょう。

java Test 2147483643
2147483643
2147483644
2147483645
2147483646
2147483647
-2147483648
-2147483647
-2147483646
-2147483645
-2147483644

2147483647の次が負の数になることがわかります。つまり,Javaの int 型の数は

1
2
3
……
2147483645
2147483646
2147483647 (= 231-1)
-2147483648 (= -231)
-2147483647
-2147483646
……
-3
-2
-1
0

のように環状になっているのです。全部で 232 通りあり,int 型の数はコンピュータの中では32ビットで表されていることがわかります。

int 型は 231-1 = 2147483647 まで表せます。この数のことを Integer.MAX_VALUE と表します。

232 通りでは足りない場合は,264 通りの数が表せる long 型を使います。この場合,最初のプログラムは次のようになります。

class Collatz {
    public static void main(String[] args) {
        long n = Long.parseLong(args[0]);
        while (n > 1) {
            if (n % 2 == 0) n = n / 2;
            else n = 3 * n + 1;
            System.out.println(n);
        }
    }
}

long 型なら 263-1 = 9223372036854775807 まで表せます。この数のことを Long.MAX_VALUE と表します。

いくら long 型でも溢れることはあります。そこで,次のようにするとよいでしょう。

class Collatz {
    static final long LIMIT = (Long.MAX_VALUE - 1) / 3;
    public static void main(String[] args) {
        long n = Long.parseLong(args[0]);
        while (n > 1) {
            if (n % 2 == 0) n = n / 2;
            else if (n <= LIMIT) n = 3 * n + 1;
            else break;
            System.out.println(n);
        }
    }
}

long 型でも足りない場合は,多倍長計算を使います。以下のものはあまり効率の良いものではありません:

import java.math.BigDecimal;

class Collatz2 {
    public static void main(String[] args) {
        BigDecimal n = new BigDecimal(args[0]);
        BigDecimal zero = new BigDecimal("0");
        BigDecimal one = new BigDecimal("1");
        BigDecimal two = new BigDecimal("2");
        BigDecimal three = new BigDecimal("3");
        while (! n.equals(one)) {
            if (n.remainder(two).equals(zero)) n = n.divide(two);
            else n = n.multiply(three).add(one);
            System.out.println(n);
        }
    }
}

奥村晴彦

Last modified: 2005-12-26 11:11:49