タクシーキャブ数

いま使っているケータイの電話番号の局番は「3312」。この数字は「33^2+12^2=3312」という変な関係を満たしている。ということを、「What's Special About This Number?」というページで知った。このページには、ほかにも

732 = 1^7 + 2^6 + 3^5 + 4^4 + 5^3 + 6^2 + 7^1
738 = 6 + 66 + 666

という何だかよく分からないけど、それなりに「おぉ」と思うものから、

734 is the smallest number that can be written as the sum of 3 distinct non-zero squares in 10 ways.

という、まったく意味があるのかどうか疑問というものまである。結構おもしろい。どこかで読んだ天才数学者ラマヌジャンのエピソードを思い出して検索してみたら、ずばりWikipediaに載っていた。

ラマヌジャンの逸話として有名なものの一つに次のものがある。

1918年2月ごろ、ラマヌジャンは療養所に入っており、見舞いに来たハーディは次のようなことを言った。

「乗ってきたタクシーのナンバーは1729だった。さして特徴のない、つまらない数字だったよ」

これを聞いたラマヌジャンは、すぐさま次のように言った。

「そんなことはありません。とても興味深い数字です。それは2通りの2つの立方数の和で表せる最小の数です」

実は、1729は次のように表すことができる。

1729 = 12^3 + 1^3 = 10^3 + 9^3

すなわち、1729が「A=B^3+C^3=D^3+E^3」という形で表すことのできる最小の数であることを、ラマヌジャンは即座に指摘したのである。

このような数字(1729)には「ハーディー・ラマヌジャン数」とか「タクシーキャブ数」という名前もついているらしい。

ともあれ、4桁の数字で、上下2桁ずつにわけた数字のそれぞれを2乗して足すと元の数字になるという数字って、ほかにあるだろうかと思って調べてみた。

1000.upto(9999){|i|
  if (i == (i / 100)**2 + (i % 100)**2)
    puts i
  end
}

結果は「1233」と「8833」の2つだけ。意外におもしろくない。あれ? と思って計算したら、3312が33^2+12^2というのは嘘じゃんということに気づいた。ていうか33*33だけで気づけよって感じだ。

で、演算子「**」は入門書を読んで知っていたはずだけど、ふつうべき乗は「^」だろうと信じ込んでいたので、こんな簡単なスクリプトでもすんなり書けない。

ついでに、6桁の上下3桁ずつに分ける場合だとどうかと思って調べたら「990100=990^2+100^2」というあまりおもしろくない感じのものしか出てこなかった。

似たような数字の組み合わせ問題で、「1^3+2^3+3^3+4^3....」を計算してみた。

1.upto(1000){|i|
  t=0
  1.upto(i){|x| t+=x*x*x}
  print i,":",t,"\n"
}

すると、「1^3+2^3+3^3+4^3……23^3+24^3=90000」というのが出てきてちょっと驚いた。しかし、先頭のほうを見てみると、

1:1
2:9
3:36
4:100
5:225
6:441
7:784
8:1296
9:2025
10:3025

となっていて、どうも階差数列の平方数が並んでいる。なんだか高校数学の数列の基礎でそんな話もあったような気もする。

1から20までの立法数を並べてみると、

01
08
27
64
125
216
343
512
729
1000

1331
1728
2197
2744
3375
4096
4913
5832
6859
8000

となっていて、1の位が「1874563290」と綺麗に周期的になっている。じゃあ下2桁で見てみるとどうなんだと思って、数えてみた。

h=Hash.new(0)

1.upto(1000){|i|
  t=0
  1.upto(i){|x| t+=x*x*x}
  h[(t%100).to_s]+=1
  print i,":",t,"\n"
}

h.each_key{|key|
  print key,":",h[key],"\n"
}

1:40
9:100
36:40
0:200
25:200
41:40
84:100
96:40
56:40
81:40
61:40
76:40
16:40
21:40

非常に限られた数字しか出てきてないようだ。特に「00」と「25」の頻度が高い。当たり前の結果のような気もする。って、だからなんだということはないけど。

ついでに計算速度が気になって、Ruby 1.8.6、Ruby 1.9.0、gcc4.2.4で比べてみた。Rubyってこのぐらい単純な計算の場合、Cに比べてどのぐらい遅いのか?

100000.upto(999999){|i|
  if (i == (i / 1000)**2 + (i % 1000)**2)
    puts i
  end
}
#include <stdio.h> 

main(void){
  int i;
  for(i=100000; i<1000000; i++){
    if(i == (i/1000)*(i/1000) + (i%1000)*(i%1000)){
      printf("%d\n",i);
    }
  }
}

結果は、

gcc  0.038秒
Ruby1.8  2.635秒
Ruby1.9  0.439秒

となった。うーん、Ruby1.9でもCとは一桁スピードが違う。そうか、そんなに違うのか。