コンパイラ

OCaml のコンパイラには ocamlc と ocamlopt の二つがある。

ocamlc バイトコードを出力。機種非依存。
ocamlopt ネイティブコードを出力。機種依存。

ocamlc の出力したバイトコードはどの機種でも動作するけど,ただし,バイトコートインタプリタというプログラムが必要――ようするに OCaml がインストールされている環境なら実行できる。

一方,ocamlopt を Windows で使うには,

  • Microsoft Visual C++ と Microsoft MASM
  • Cygwin環境

のどちらかが必要になる。

Visual C++ は Express Edition がインストールしてあるんだけど,これだけじゃだめだった。まぁ,ocamlcを使えばいいか。

ごく基本的な使い方はこんなふう。

^o^ >ocamlc -o hello.exe hello.ml

-o オプションは出力するファイル名を指定する。Windowsでは .exe もつけること。-o オプションを省略すると camlprog.exe という名前になる。

Probrem 21

今日は Probrem 21 をやってみた。

 cf. http://projecteuler.net/index.php?section=problems&id=21

数 n に対して約数(nを含まない)すべてを足しあわせる関数 d があるとして,d(a) = b かつ d(b) = a となるような a と b (ただしa≠b)を amicable pair,それぞれを amicable number という(んだそうだ)。で,10000未満の amicable number をすべて足しあわせろ,という問題。
内包表記大活躍……なのはいいけど,すっげー時間がかかる。10000未満なんてやったら待ってられないので,下のコードでは1000未満にしてある。いい方法はないだろうか。

module Main (main) where

d :: Int -> Int
d n = sum [x | x <- [1..(n `div` 2)], n `mod` x == 0]

euler021 :: Int -> Int
euler021 n = sum $ map (\(a,b) -> a + b) pairs
  where
    pairs = [(a,b) | a <- [1..n], b <- [1..n], a < b, d a == b, d b == a]

main :: IO ()
main = print $ euler021 1000
^o^ >euler021.exe
504

1000未満では 220 と 284 のペアしかないみたいだ。

追記:

いい方法はないだろうか,と書いたらコメントやらトラックバックやらでいろいろ教えてくれた。ありがとうございます。

 cf. http://haskell.g.hatena.ne.jp/nobsun/20080314/p1

おおっ,速い!

追記2:

ううっ,うっかりとエントリに上書きして消してしまった。できるだけ復元したけど元のエントリとは少し違ってるかも。

Project Euler

ってのがあるのか。

 cf. http://projecteuler.net/index.php
 via Life Goes On – はじめました

気が向いたときにはやってみるかな。
とりあえず Problem 1 を内包表記で。

euler0001 :: Int -> Int
euler0001 n = sum [x | x <- [1..(n-1)], or [x `mod` 3 == 0, x `mod` 5 == 0]]

main :: IO ()
main = print $ euler0001 1000
^o^ >runhaskell euler0001.hs
233168

コラッツ予想

cf. Way of My Life – コラッツ予想

Haskell と OCaml でやってみた。
与えられた数から1になるまでをリストで返す。

collatz :: Int -> [Int]
collatz 1 = 1 : []
collatz n | n `mod` 2 == 0 = n : collatz (n `div` 2)
          | otherwise = n : collatz (n * 3 + 1)
*Main> collatz 19
[19,58,29,88,44,22,11,34,17,52,26,13,40,20,10,5,16,8,4,2,1]

割り算には値を整数で返す div を使っている。はじめ / を使ったら型があわずにエラーになった。

今度は OCaml 版。やってることはおんなじ。

let rec collatz = function
    1 -> 1 :: []
    | n when n mod 2 = 0 -> n :: collatz (n / 2)
    | n -> n :: collatz (n * 3 + 1)
# collatz 19;;
- : int list =
[19; 58; 29; 88; 44; 22; 11; 34; 17; 52; 26; 13; 40; 20; 10; 5; 16; 8; 4; 2; 1]