Skip to content
This repository was archived by the owner on May 22, 2026. It is now read-only.

Commit 2f0a875

Browse files
Merge pull request #12 from RyosukeDTomita/feature/why_functional_programming_matters
feat: convert to Haskell
2 parents 7f660c0 + f2fa3e2 commit 2f0a875

2 files changed

Lines changed: 152 additions & 0 deletions

File tree

math/differential/differential.hs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
-- https://www.sampou.org/haskell/article/whyfp.html
2+
import Control.Arrow (Arrow (second))
3+
import Data.Semigroup (diff)
4+
5+
-- 傾きをもとめる
6+
easyDiff :: (Fractional a) => (a -> a) -> a -> a -> a
7+
easyDiff f x h = (f (x + h) - f x) / h
8+
9+
differentiate :: Double -> (Double -> Double) -> Double -> [Double]
10+
differentiate h0 f x = map (easyDiff f x) (iterate halve h0)
11+
where
12+
halve x = x / 2
13+
14+
-- 許容誤差と近似値よりも差の小さい2つの連続する近似値を探す
15+
within :: Double -> [Double] -> Double
16+
within eps (a : b : rest)
17+
| abs (a - b) <= eps = b -- 絶対誤差
18+
| otherwise = within eps (b : rest)
19+
20+
-- テスト用の関数
21+
square :: Double -> Double
22+
square x = x ** 2
23+
24+
-- 誤差を消去するリスト変換
25+
-- a = a(i)
26+
-- b = b(i+1)
27+
-- a(i+1)*(2**n) - a(i)
28+
-- A = --------------------
29+
-- 2**n - 1
30+
elimerror :: Int -> [Double] -> [Double]
31+
elimerror n (a : b : rest) =
32+
((b * (2 ** fromIntegral n) - a) / (2 ** fromIntegral n - 1)) : elimerror n (b : rest)
33+
34+
-- nを求められるらしい。
35+
order :: [Double] -> Int
36+
order (a : b : c : _) =
37+
round (logBase 2 ((a - c) / (b - c) - 1))
38+
39+
improve :: [Double] -> [Double]
40+
improve s = elimerror (order s) s
41+
42+
-- 複数回improveすると急速に高い結果をもたらす
43+
super :: [Double] -> [Double]
44+
super s = map second (iterate improve s)
45+
where
46+
second (a : b : rest) = b
47+
48+
main :: IO ()
49+
main = do
50+
let eps = 0.001
51+
let h0 = 0.1
52+
let x = 3
53+
print $ within eps (differentiate h0 square x)
54+
-- より良い近似
55+
print $ within eps (improve (differentiate h0 square x))
56+
-- improveを複数回やると効率良く近似できる
57+
print $ within eps (improve (improve (improve (differentiate h0 square x))))
58+
-- 複数回improveするものの改良版
59+
print $ within eps (super (differentiate h0 square x))

math/integrate/integrate.hs

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
-- https://www.sampou.org/haskell/article/whyfp.html
2+
easyIntegrate :: (Fractional a) => (a -> a) -> a -> a -> a
3+
easyIntegrate f a b = (f a + f b) * (b - a) / 2
4+
5+
integrate :: (Double -> Double) -> Double -> Double -> [Double]
6+
integrate f a b =
7+
easyIntegrate f a b
8+
: zip'
9+
(integrate f a mid)
10+
(integrate f mid b)
11+
where
12+
mid = (a + b) / 2
13+
14+
-- fa fm fbの値をキャッシュすることで効率化したバージョン
15+
-- integrate' :: (Double -> Double) -> Double -> Double -> [Double]
16+
-- integrate' f a b = integ f a b (f a) (f b)
17+
-- where
18+
-- integ f a b fa fb = ((fa + fb) * (b - a) / 2) : zipWith (+) (integ f a m fa fm) (integ f m b fm fb)
19+
-- m = (a + b) / 2 -- NOTE: この実装だとmとfmが束縛されてしまい、すべてのintegに対して同じ値を使うので不適切
20+
-- fm = f m
21+
integrate' :: (Double -> Double) -> Double -> Double -> [Double]
22+
integrate' f a b = integ a b (f a) (f b)
23+
where
24+
integ a b fa fb =
25+
let m = (a + b) / 2
26+
fm = f m
27+
in ((fa + fb) * (b - a) / 2)
28+
: zipWith
29+
(+)
30+
(integ a m fa fm)
31+
(integ m b fm fb)
32+
33+
-- 誤差を消去するリスト変換
34+
-- a = a(i)
35+
-- b = b(i+1)
36+
-- a(i+1)*(2**n) - a(i)
37+
-- A = --------------------
38+
-- 2**n - 1
39+
elimerror :: Int -> [Double] -> [Double]
40+
elimerror n (a : b : rest) =
41+
((b * (2 ** fromIntegral n) - a) / (2 ** fromIntegral n - 1)) : elimerror n (b : rest)
42+
43+
-- nを求められるらしい。
44+
order :: [Double] -> Int
45+
order (a : b : c : _) =
46+
round (logBase 2 ((a - c) / (b - c) - 1))
47+
48+
improve :: [Double] -> [Double]
49+
improve s = elimerror (order s) s
50+
51+
-- 複数回improveすると急速に高い結果をもたらす
52+
super :: [Double] -> [Double]
53+
super s = map second (iterate improve s)
54+
where
55+
second (a : b : rest) = b
56+
57+
zip' :: (Num a) => [a] -> [a] -> [a]
58+
zip' (a : s) (b : t) = a + b : (zip' s t)
59+
zip' _ _ = []
60+
61+
zip'' :: (Num a) => [a] -> [a] -> [a]
62+
zip'' as bt = zipWith (+) as bt
63+
64+
-- 許容誤差と近似値よりも差の小さい2つの連続する近似値を探す
65+
within :: Double -> [Double] -> Double
66+
within eps (a : b : rest)
67+
| abs (a - b) <= eps = b -- 絶対誤差
68+
| otherwise = within eps (b : rest)
69+
70+
relative :: Double -> [Double] -> Double
71+
relative eps (a : b : rest)
72+
| abs (a - b) <= eps * abs b = b -- abs (a - b) / abs b <= epsを変形したもの。いわゆる相対誤差
73+
| otherwise = relative eps (b : rest)
74+
75+
square :: Double -> Double
76+
square x = x * x
77+
78+
main :: IO ()
79+
main = do
80+
-- print $ zip' [1, 2] [3, 4] -- [4, 6]
81+
-- print $ zip'' [1, 2] [3, 4] -- [4, 6]
82+
let eps = 0.001
83+
let a = 0
84+
let b = 3
85+
print $ within eps (integrate' square a b) -- x^2を積分すると(1/3) * x^3なので
86+
print $ relative eps (integrate' square a b)
87+
88+
-- 高速にsinの積分を求める例
89+
-- print $ improve (integrate' sin 0 4)
90+
91+
-- π/4
92+
let f x = 1 / (1 + x * x)
93+
print $ within eps (super (integrate' f 0 1))

0 commit comments

Comments
 (0)