intime o'

みんなあいつの幻想だもの。そうだよ、何も悲しいことなんてないや。さ、おいで! (ルイス・キャロル著「不思議の国のアリス」より)
速さが正義だというつまらない話 2012/08/24(Fri.)
あるこんなブログの記事
「HaskellとOCamlの速度を比較してみた」(http://d.hatena.ne.jp/hideshi_o/touch/20120823/1345732820)
言語別の速度比較をしているのだけど、それぞれの言語についてただとにかく
速いものに洗練した結果同士を比べることになる.その洗練する作業はどこかで
打ち切らないといけないのだけれど.コメントがちょっとイラッと来た.

以下のコードをそれぞれ -O2 オプション付きでghcコンパイルして、それぞれ
一度ずつ速度を測ってみた.

import Data.List
main =
    print $
    maximum $
    filter (\x -> reverse(show x) == show x) $
    [x*y | x <- [100 .. 999], y <- [x .. 999]]
-- real:    0.748000 sec.
-- user:    0.639604 sec.
-- kernel:  0.000000 sec.

記事の中で最終的に「追記2」として使われてたコード、大体そのまま.
よくわからないけど、999*999 以下の整数で回文数となってるものの
内最大のものを計算して出力するプログラムということだろう.だから
下限は実際問題ではないのだけど.

show は任意の型のものを文字列にする関数.
任意の型を受け付けるだなんて、普通のhaskellで書く関数とは
意味が違うだろうから、あんまり使いたくない.show自体にかかる
計算時間もバカにできないんじゃないか.

(int x) が回文数であるか判定する述語として
(reverse(show x))==(show x)
を使っていて、よくわからないからこれでいいけど、(show x)は一度
計算したら変数にもっておこう.

import Data.List
main =
    print $
    maximum $
    filter (\x -> let s = show x in reverse s == s) $
    [x*y | x <- [100 .. 999], y <- [x .. 999]]
-- real:    0.499000 sec.
-- user:    0.405603 sec.
-- kernel:  0.000000 sec.

show の使用回数は一度に留められる.

内包表記で書いたリストに対して直接filterをしているけれど、
内包表記ってのはそもそも次のような書き方をするためのものだろう.

import Data.List
main =
    print $
    maximum $
    [x*y | x <- [100 .. 999], y <- [x .. 999],
        let s = show $ x * y in reverse s == s]
-- real:    0.327000 sec.
-- user:    0.265202 sec.
-- kernel:  0.015600 sec.

地味に少し速くなっている.
さっき別のlinux機でfilter版と内包表記に含める版との差はほとんど
無かったのだけれど.

私が上をコメントに書いたら、筆者でもない誰かが私のコードを含めた
ものをまとめとか勝手に言って書いてたけど、let束縛をlet文にしてた.

import Data.List
main =
    print $
    maximum $
    [z | x <- [100 .. 999], y <- [x .. 999],
        let z = x * y,
        let s = show z,
        reverse s == s]
-- real:    0.468000 sec.
-- user:    0.390002 sec.
-- kernel:  0.031200 sec.

手続き型言語的な脳で考えると、letは少しスコープの広い変数を
定義してるようなものだから、しかも2つもやってると時間が余計に
かかりそうだ.正直嫌だ. 

コメ(0) | トラ(0)