for文マンセー
朝、出かける前にレクリエーション数学の本をぱらっと見たら、3辺のうちいずれか1本の長さが48となる直角三角形は10個ある、というようなことが書いてあった。詳細は見なかったけど、よほど多いということなんだろうか。
Haskellの例題として、これを検証してみようと思った。で、こういうのは先に答えを知ってるほうがいいだろうと思って、ひとまずCで計算してみた。
#include <stdio.h> #include <stdlib.h> int main() { for (int x = 1; x < 200; x++) { printf ("-----(%3d)------\n", x); for (int i = 1; i < 40000; i++) { for (int j = 1; j < 40000; j++) { if (i*i == x*x + j*j) { printf ("%5d^2 + %5d^2 = %6d^2\n", j, x, i); } } } } return 0; }
結果のうち48近辺を引用すると:
-----( 29)------ 420^2 + 29^2 = 421^2 -----( 30)------ 16^2 + 30^2 = 34^2 40^2 + 30^2 = 50^2 72^2 + 30^2 = 78^2 224^2 + 30^2 = 226^2 -----( 31)------ 480^2 + 31^2 = 481^2 -----( 32)------ 24^2 + 32^2 = 40^2 60^2 + 32^2 = 68^2 126^2 + 32^2 = 130^2 255^2 + 32^2 = 257^2 -----( 33)------ 44^2 + 33^2 = 55^2 56^2 + 33^2 = 65^2 180^2 + 33^2 = 183^2 544^2 + 33^2 = 545^2 -----( 34)------ 288^2 + 34^2 = 290^2 -----( 35)------ 12^2 + 35^2 = 37^2 84^2 + 35^2 = 91^2 120^2 + 35^2 = 125^2 612^2 + 35^2 = 613^2 -----( 36)------ 15^2 + 36^2 = 39^2 27^2 + 36^2 = 45^2 48^2 + 36^2 = 60^2 77^2 + 36^2 = 85^2 105^2 + 36^2 = 111^2 160^2 + 36^2 = 164^2 323^2 + 36^2 = 325^2 -----( 37)------ 684^2 + 37^2 = 685^2 -----( 38)------ 360^2 + 38^2 = 362^2 -----( 39)------ 52^2 + 39^2 = 65^2 80^2 + 39^2 = 89^2 252^2 + 39^2 = 255^2 760^2 + 39^2 = 761^2 -----( 40)------ 9^2 + 40^2 = 41^2 30^2 + 40^2 = 50^2 42^2 + 40^2 = 58^2 75^2 + 40^2 = 85^2 96^2 + 40^2 = 104^2 198^2 + 40^2 = 202^2 399^2 + 40^2 = 401^2 -----( 41)------ 840^2 + 41^2 = 841^2 -----( 42)------ 40^2 + 42^2 = 58^2 56^2 + 42^2 = 70^2 144^2 + 42^2 = 150^2 440^2 + 42^2 = 442^2 -----( 43)------ 924^2 + 43^2 = 925^2 -----( 44)------ 33^2 + 44^2 = 55^2 117^2 + 44^2 = 125^2 240^2 + 44^2 = 244^2 483^2 + 44^2 = 485^2 -----( 45)------ 24^2 + 45^2 = 51^2 28^2 + 45^2 = 53^2 60^2 + 45^2 = 75^2 108^2 + 45^2 = 117^2 200^2 + 45^2 = 205^2 336^2 + 45^2 = 339^2 1012^2 + 45^2 = 1013^2 -----( 46)------ 528^2 + 46^2 = 530^2 -----( 47)------ 1104^2 + 47^2 = 1105^2 -----( 48)------ 14^2 + 48^2 = 50^2 20^2 + 48^2 = 52^2 36^2 + 48^2 = 60^2 55^2 + 48^2 = 73^2 64^2 + 48^2 = 80^2 90^2 + 48^2 = 102^2 140^2 + 48^2 = 148^2 189^2 + 48^2 = 195^2 286^2 + 48^2 = 290^2 575^2 + 48^2 = 577^2 -----( 49)------ 168^2 + 49^2 = 175^2 1200^2 + 49^2 = 1201^2 -----( 50)------ 120^2 + 50^2 = 130^2 624^2 + 50^2 = 626^2 -----( 51)------ 68^2 + 51^2 = 85^2 140^2 + 51^2 = 149^2 432^2 + 51^2 = 435^2 1300^2 + 51^2 = 1301^2 -----( 52)------ 39^2 + 52^2 = 65^2 165^2 + 52^2 = 173^2 336^2 + 52^2 = 340^2 675^2 + 52^2 = 677^2 -----( 53)------ 1404^2 + 53^2 = 1405^2 -----( 54)------ 72^2 + 54^2 = 90^2 240^2 + 54^2 = 246^2 728^2 + 54^2 = 730^2 -----( 55)------ 48^2 + 55^2 = 73^2 132^2 + 55^2 = 143^2 300^2 + 55^2 = 305^2 1512^2 + 55^2 = 1513^2 -----( 56)------ 33^2 + 56^2 = 65^2 42^2 + 56^2 = 70^2 90^2 + 56^2 = 106^2 105^2 + 56^2 = 119^2 192^2 + 56^2 = 200^2 390^2 + 56^2 = 394^2 783^2 + 56^2 = 785^2
確かに48だと多めだけど、取り立てて面白くない。当たり前のような。
むしろ、
-----(193)------ 18624^2 + 193^2 = 18625^2 -----(194)------ 9408^2 + 194^2 = 9410^2
のあたりのほうが面白い。
ともあれ、これをHaskellとかRubyで計算するにはどうするんだろうかなと思って、permutationで組み合わせを作って、48を含むものでfilterして……、とか考えていたけど、はっきり言ってfor文万歳でいいやんかという例題でしかなかった。
と、いいつつRubyでやってみた。1から200までの数字の3つの組み合わせで直角三角形になっているもののリストを作って、このうち48が含まれるものを探す。
a = (1..200).to_a.combination(3).find_all{|i| i[0]**2+i[1]**2 == i[2]**2} => [[3, 4, 5], [5, 12, 13], [6, 8, 10], [7, 24, 25], [8, 15, 17], [9, 12, 15], [9, 40, 41], [10, 24, 26], [11, 60, 61], [12, 16, 20], [12, 35, 37], [13, 84, 85], [14, 48, 50], [15, 20, 25], [15, 36, 39], [15, 112, 113], [16, 30, 34], [16, 63, 65], [17, 144, 145], [18, 24, 30], [18, 80, 82], [19, 180, 181], [20, 21, 29], [20, 48, 52], [20, 99, 101], [21, 28, 35], [21, 72, 75], [22, 120, 122], [24, 32, 40], [24, 45, 51], [24, 70, 74], [24, 143, 145], [25, 60, 65], [26, 168, 170], [27, 36, 45], [27, 120, 123], [28, 45, 53], [28, 96, 100], [28, 195, 197], [30, 40, 50], [30, 72, 78], [32, 60, 68], [32, 126, 130], [33, 44, 55], [33, 56, 65], [33, 180, 183], [35, 84, 91], [35, 120, 125], [36, 48, 60], [36, 77, 85], [36, 105, 111], [36, 160, 164], [39, 52, 65], [39, 80, 89], [40, 42, 58], [40, 75, 85], [40, 96, 104], [42, 56, 70], [42, 144, 150], [44, 117, 125], [45, 60, 75], [45, 108, 117], [48, 55, 73], [48, 64, 80], [48, 90, 102], [48, 140, 148], [48, 189, 195], [49, 168, 175], [50, 120, 130], [51, 68, 85], [51, 140, 149], [52, 165, 173], [54, 72, 90], [55, 132, 143], [56, 90, 106], [56, 105, 119], [56, 192, 200], [57, 76, 95], [57, 176, 185], [60, 63, 87], [60, 80, 100], [60, 91, 109], [60, 144, 156], [60, 175, 185], [63, 84, 105], [64, 120, 136], [65, 72, 97], [65, 156, 169], [66, 88, 110], [66, 112, 130], [69, 92, 115], [70, 168, 182], [72, 96, 120], [72, 135, 153], [72, 154, 170], [75, 100, 125], [75, 180, 195], [78, 104, 130], [78, 160, 178], [80, 84, 116], [80, 150, 170], [81, 108, 135], [84, 112, 140], [84, 135, 159], [85, 132, 157], [87, 116, 145], [88, 105, 137], [88, 165, 187], [90, 120, 150], [93, 124, 155], [95, 168, 193], [96, 110, 146], [96, 128, 160], [99, 132, 165], [99, 168, 195], [100, 105, 145], [102, 136, 170], [104, 153, 185], [105, 140, 175], [108, 144, 180], [111, 148, 185], [114, 152, 190], [117, 156, 195], [119, 120, 169], [120, 126, 174], [120, 160, 200], [130, 144, 194]] >> a.find_all{|i| i.member?(48)} => [[14, 48, 50], [20, 48, 52], [36, 48, 60], [48, 55, 73], [48, 64, 80], [48, 90, 102], [48, 140, 148], [48, 189, 195]]
8つしか見つかってないけど、上限を上げれば10個見つかる。
48が含まれる組み合わせ以外でも2乗の計算をしまくってるのは効率が悪いので、本当は順序が逆なんだろうけど。
うーん、この例だと、member?(48)の結果はリスト中で最初にマッチした値が戻ってくる。もし含まれないとnil。ということは、すべてを1つのメソッドチェーンにしようと思っても、Nil#find_allなんてメソッドはないよと怒られるということか。このへんがMaybeモナドのいいところかしら?