コラッツ・角谷の問題
Posted feedbacks - C
これ、キミならどう書く 2.0 - ROUND 2 -と同じ問題ですね。違うのは、LL Ringの時の「どう書く」では、1の時も1と数えるので、1違うだけで。
その時にいろいろ書いて出来た最速の奴を。j詳しくは404 Blog Not Found:h(4294967295) = 2610744987 where g = 1051 をご覧下さい。
途中経過表示をやめれば、もっと速くなるでしょう。
Dan the Number Cruncher
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 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | /*
Core 2 Duo 2.33GHzで
% time ./a.out 1000000
h(1000000) = 837799 where g(837799) = 525
0.264u 0.006s 0:00.27 96.2% 0+0k 0+0io 0pf+0w
*/
#include <stdio.h>
#include <stdlib.h>
#ifndef CACHE_SIZE
#define CACHE_SIZE 64*1024*1024 /* large enough */
#endif
#define MAX_U16 65535
typedef unsigned short U16;
typedef long long I64;
U16 *cache;
int cachesize;
#define lookup(n) ((n) < cachesize ? cache[(n)] : 0)
#define store(n,g) if ((n) < cachesize && g <= MAX_U16) cache[(n)] = (g)
I64 g(I64 n){
I64 result = lookup(n);
if (result) return result;
I64 i = n;
I64 l;
result = 1;
while (i > 1){
i = i & 1 ? i*3+1 : i >> 1;
l = lookup(i);
if (l){
result += l;
break;
}else{
result++;
}
}
if (i < 1) fprintf(stderr, "overflow! g(%qd) = %qd\n", n, i);
store(n, result);
return result;
}
I64 *h(I64 n){
I64 i, nmax = 0, gmax = 0, gnext = 0;
static I64 result[2];
for (i = n; i > 1 ; i--){
gnext = g(i);
#ifdef VERBOSE
fprintf(stderr, "g(%qd) = %qd\r", i, gnext);
#endif
if (gnext > gmax){
nmax = i; gmax = gnext;
}
if (i & 0xffff) continue;
printf("nmax = %qd, gmax = %qd, n = %qd\r", nmax, gmax, i);
fflush(stdout);
}
result[0] = nmax; result[1] = gmax;
return result;
}
#define min(x,y) ((x) < (y) ? (x) : (y))
void init_cache(I64 n){
cachesize = min(n, CACHE_SIZE);
cache = (U16 *)calloc(cachesize, sizeof(U16));
if (cache == NULL) exit(-1);
}
int main(int argc, char **argv){
I64 n = 0xffffffff; /* look @ this! */
if (argc > 1){
n = atoll(argv[1]);
}
init_cache(n);
I64 *hg = h(n);
printf("h(%qd) = %qd where g(%qd) = %qd\n", n, hg[0], hg[0], hg[1]);
return 0;
}
|
というわけでCで書き直した。 実行結果@AthlonXP2500+ ---- f(837799)=524 time=0.093000sec
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 36 37 38 39 40 41 42 43 44 45 | #include <stdio.h>
#include <string.h>
#include <time.h>
#define NMAX 1048576
short memo[NMAX];
int _f(unsigned long long n)
{
int step;
if(n == 1)
return 0;
if(n < NMAX && memo[n] != 0)
return memo[n];
if(n & 1)
step = _f(n * 3 + 1) + 1;
else
step = _f(n >> 1) + 1;
if(n < NMAX)
memo[n] = step;
return step;
}
int main(void)
{
int i,mf,mi;
mf = 0;
memset(memo, 0, NMAX * sizeof(short));
for(i = 1;i < NMAX; ++i) {
if (memo[i] == 0){
_f(i);
}
if (memo[i] > mf){
mi = i;
mf = memo[i];
}
}
printf("f(%d)=%d\ntime=%fsec", mi,mf, (double)clock() / CLOCKS_PER_SEC);
}
|
C に移植したバージョン。
最近の gcc は、コンパイル時に -O2 を付けると末尾再帰呼び出しを最適化してくれるようですね。便利。
実行例:
$ cc -O2 -o collatz collatz.c
$ time ./collatz
n=837799, steps=524
./collatz 0.07s user 0.00s system 95% cpu 0.079 total
やはりネイティブコンパイルできる処理系は早いですね。
最近の gcc は、コンパイル時に -O2 を付けると末尾再帰呼び出しを最適化してくれるようですね。便利。
実行例:
$ cc -O2 -o collatz collatz.c
$ time ./collatz
n=837799, steps=524
./collatz 0.07s user 0.00s system 95% cpu 0.079 total
やはりネイティブコンパイルできる処理系は早いですね。
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 36 37 38 39 40 41 42 43 44 | #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LIMIT 1048576
int solve_collatz(long n, int step, int *cache){
if(n == 1)
return step;
else if(n <= LIMIT && cache[n] != 0)
return step + cache[n];
else if(0 == n % 2)
return solve_collatz(n/2, step+1, cache);
else
return solve_collatz(n*3+1, step+1, cache);
}
long set_doubles(long i, int *steps, int *cache){
for(;i <= LIMIT; i *= 2, (*steps)++)
cache[i] = *steps;
*steps -= 1;
return i/2;
}
int main(){
int *cache, steps, max_steps = 0;
long n, mc_n, max_n = 0;
cache = malloc((LIMIT + 1) * sizeof(int));
if(!cache) exit(1);
memset(cache, 0, (LIMIT + 1) * sizeof(int));
for(n = 1; n <= LIMIT; n++){
if(cache[n] == 0){
steps = solve_collatz(n, 0, cache);
mc_n = set_doubles(n, &steps, cache);
if(max_steps < steps){
max_n = mc_n;
max_steps = steps;
}
}
}
printf("n=%d, steps=%d\n", max_n, cache[max_n]);
}
|




ところてん
#4969()
Rating2/2=1.00
see: コラッツの問題の成り立つ範囲
[ reply ]