コラッツの問題

このエントリーをはてなブックマークに追加

d:id:tamura70:20100113:collatz と同様に, n が 2k+r について場合分けすることで,コラッツの問題を調べるプログラムを高速化する.

プログラム

以下のプログラムでは, 222 で割った余りについて場合分けし,あらかじめ表を作成している.
すなわち,222 で割った商が q 余りが r の時, c[r].len ステップ後に c[r].x * q + c[r].y になる.
また,さらに q=0 の場合は,別に表 t[r] を作成している.

#include <stdio.h>
#include <sys/types.h>
#include <sys/times.h>
#include <sys/param.h>

#define BITS	(22)
#define MOD	(1 << BITS)

typedef unsigned long long ULONG;

struct {
    ULONG x;
    ULONG y;
    int len;
} c[MOD];

int t[MOD];

double t0;

void init() {
    ULONG x, y, n;
    int i, len;

    for (i = 0; i < MOD; i++) {
	x = MOD;
	y = i;
	len = 0;
	while (x % 2 == 0) {
	    if (y % 2 == 0) {
		x /= 2;
		y /= 2;
	    } else {
		x *= 3;
		y = 3*y + 1;
	    }
	    len++;
	}
	c[i].x = x;
	c[i].y = y;
	c[i].len = len;
    }

    t[1] = 1;
    for (i = 2; i < MOD; i++) {
	len = 0;
	n = i;
	while (n >= i) {
	    n = (n%2 == 0) ? n/2 : 3*n+1;
	    len++;
	}
	t[i] = len + t[n];
    }
}

double usertime() {
    struct tms buffer;

    times(&buffer);
    return (double)buffer.tms_utime/HZ;
}

void solve() {
    ULONG n0, n;
    int max, len, len1, r;
    double t0, t1;

    max = 1;
    for (n0 = 1; ; n0 += 2) {
	n = n0;
	len = 0;
	while (n != 1) {
	    if (n < MOD) {
		len += t[n];
		break;
	    }
	    r = n % MOD;
	    n = (ULONG)c[r].x * (n/MOD) + c[r].y;
	    len += c[r].len;
	}
	if (len > max) {
	    max = len;
	    t1 = usertime() - t0;
	    printf("n=%15qd len=%5d (%.1lf sec)\n", n0, len, t1);
	    fflush(stdout);
	}
    }
}

int main(int argc, char *argv[]) {
    t0 = usertime();
    printf("Generating table\n");
    fflush(stdout);
    init();
    printf("Start\n");
    fflush(stdout);
    solve();
}

実行例

Let's Note CF-W5で解いた結果

Generating table
Start
n=              3 len=    8 (3.3 sec)
n=              7 len=   17 (3.3 sec)
n=              9 len=   20 (3.3 sec)
n=             19 len=   21 (3.3 sec)
n=             25 len=   24 (3.3 sec)
n=             27 len=  112 (3.3 sec)
n=             55 len=  113 (3.3 sec)
n=             73 len=  116 (3.3 sec)
n=             97 len=  119 (3.3 sec)
n=            129 len=  122 (3.3 sec)
n=            171 len=  125 (3.3 sec)
n=            231 len=  128 (3.3 sec)
n=            313 len=  131 (3.3 sec)
n=            327 len=  144 (3.3 sec)
n=            649 len=  145 (3.3 sec)
n=            703 len=  171 (3.3 sec)
n=            871 len=  179 (3.3 sec)
n=           1161 len=  182 (3.3 sec)
n=           2223 len=  183 (3.3 sec)
n=           2463 len=  209 (3.3 sec)
n=           2919 len=  217 (3.3 sec)
n=           3711 len=  238 (3.3 sec)
n=           6171 len=  262 (3.3 sec)
n=          10971 len=  268 (3.3 sec)
n=          13255 len=  276 (3.3 sec)
n=          17647 len=  279 (3.3 sec)
n=          23529 len=  282 (3.3 sec)
n=          26623 len=  308 (3.3 sec)
n=          34239 len=  311 (3.3 sec)
n=          35655 len=  324 (3.3 sec)
n=          52527 len=  340 (3.3 sec)
n=          77031 len=  351 (3.3 sec)
n=         106239 len=  354 (3.3 sec)
n=         142587 len=  375 (3.3 sec)
n=         156159 len=  383 (3.3 sec)
n=         216367 len=  386 (3.3 sec)
n=         230631 len=  443 (3.3 sec)
n=         410011 len=  449 (3.3 sec)
n=         511935 len=  470 (3.3 sec)
n=         626331 len=  509 (3.3 sec)
n=         837799 len=  525 (3.3 sec)
n=        1117065 len=  528 (3.3 sec)
n=        1501353 len=  531 (3.3 sec)
n=        1723519 len=  557 (3.3 sec)
n=        2298025 len=  560 (3.4 sec)
n=        3064033 len=  563 (3.4 sec)
n=        3542887 len=  584 (3.4 sec)
n=        3732423 len=  597 (3.4 sec)
n=        5649499 len=  613 (3.4 sec)
n=        6649279 len=  665 (3.5 sec)
n=        8400511 len=  686 (3.5 sec)
n=       11200681 len=  689 (3.7 sec)
n=       14934241 len=  692 (3.9 sec)
n=       15733191 len=  705 (3.9 sec)
n=       31466383 len=  706 (4.7 sec)
n=       36791535 len=  745 (5.0 sec)
n=       63728127 len=  950 (6.5 sec)
n=      127456255 len=  951 (10.2 sec)
n=      169941673 len=  954 (12.7 sec)
n=      226588897 len=  957 (16.1 sec)
n=      268549803 len=  965 (18.6 sec)
n=      537099607 len=  966 (35.5 sec)
n=      670617279 len=  987 (44.0 sec)
n=     1341234559 len=  988 (88.8 sec)
n=     1412987847 len= 1001 (93.6 sec)
n=     1674652263 len= 1009 (111.3 sec)
n=     2610744987 len= 1051 (176.2 sec)
n=     4578853915 len= 1088 (317.0 sec)
n=     4890328815 len= 1132 (339.9 sec)
n=     9780657631 len= 1133 (713.6 sec)
n=    12212032815 len= 1154 (928.3 sec)
n=    12235060455 len= 1185 (930.3 sec)
n=    13371194527 len= 1211 (1031.5 sec)
n=    17828259369 len= 1214 (1424.8 sec)