fortran66のブログ

fortran について書きます。

分割数 p(n) の直接計算 Haskell 版

ずいぶん前に Hutton の Haskell 本を読んで、階乗くらいしかプログラムを書かずに放置していましたが、夏にもう一度勉強しようかなと思ってみました。

とりあえず Fortran で書いた 分割数 p(n) の直接計算を移植してみることにしました。文法をよく知らないのでものすごく時間がかかりました。結果が微妙におかしい感じがしますが、デバッグ・プリントが難しくてあきらめました。

fortran66.hatenablog.com

実行結果

インストールするのもかったるいのでオンライン・コンパイラにて。
Free Online IDE and Terminal

1から10までの分割数、1,2,3,5,7,11,15,22,30,42 を計算しています。

sh-4.3$ ghc -O2 --make *.hs -o main -threaded -rtsopts                                                                                                                                           
[1 of 1] Compiling Main             ( main.hs, main.o )                                                                                                                                          
Linking main ...                                                                                                                                                                                 
sh-4.3$ main                                                                                                                                                                                     
[0.9810639,2.0009859,3.0242445,5.014357,6.9633565,11.030045,14.987319,21.990871,30.022284,41.988766]                                                                                             
sh-4.3$ ^C  

ソース・プログラム

複素数の使い方が分からなくて泣きました。型変換がよく分からなくて・・・

import Data.Complex

dsn :: RealFloat a => Int -> a -> a 
dsn k z = ( f * cosh(f * x) - sinh(f * x) / x ) / (2 * x * x)
          where f = pi / fromIntegral k * sqrt(2.0 / 3.0)
                x = sqrt(z - 1.0 / 24.0)

f :: RealFloat a => Int -> Int -> Int -> a -> Complex a
f n k h x = (sqrt (fromIntegral k) / (pi * sqrt 2.0) :+ 0.0) * exp (0:+ x) * (dsn k (fromIntegral n):+ 0.0) 

w :: Int -> Int -> Int -> Float
w n k h = pi * (w1 n k h + w2 k h)

w1 :: Int -> Int -> Int -> Float
w1 n k h = (-2.0) * (fromIntegral n) * (fromIntegral h) / (fromIntegral k) 

w2 :: Int -> Int -> Float
w2   k h = sum [(fromIntegral j) / (fromIntegral k) * (frac ((fromIntegral h) * (fromIntegral j) / (fromIntegral k)) - 0.5) |j <- [1..k-1]]

frac :: Float -> Float
frac x = x - fromIntegral (floor x)

gg :: Int -> [Complex Float]
gg n = [f n k h (w n k h) | k <- [1..], h <- [1..k], gcd k h == 1]

partition :: Int -> Float
partition n = realPart ( sum (take max_k (gg n)) )
             where max_k = 10

main = print ([partition i| i <- [1..10]])