2017年10月26日木曜日

stern-brocot 木

stern-brocot 木
Stern-Brocot 木の「親」の値は数直線の区間です。
頂点の親「根」の値は
0〜∞
左端が0で、右は無限大です。
それを分数で0/1、1/0とそれぞれ表します。
さらにHaskellではタプルで
(0,1) ,(1,0)
と表します。
つまりHaskellでStern-Brocot 木の根はタプルのタプルで
((0,1) ,(1,0))
と表せます。
親はいつでも自動で左の子、右の子を生成することができます。
Haskellで書くとこのような関数になります。

sb ((x,y),(z,w)) = (a,b)  where  a = ((x,y),c) ; b = (c,(z,w)); c = (z+x,y+w)

aが左の子bが右の子です。左の子の右端と右の子の左端は同じです。分割点になります。

main = do
    let a = (0,1)
    let b = (1,0)
    let r = (a,b)
    print r
    print $ sb r

((0,1),(1,0))
(((0,1),(1,1)),((1,1),(1,0)))

数直線の区間
0〜∞

0〜1

1〜∞
の2つの区間に分割したのと同じです。

もう一世代増やしてみましょう。

main = do
    let a = (0,1)
    let b = (1,0)
    let r = (a,b)
   
    let (a,b) = sb r
    print $ sb a
    print $ sb b

(((0,1),(1,2)),((1,2),(1,1)))
(((1,1),(2,1)),((2,1),(1,0)))

これは
数直線の区間
0〜1

0〜0.5

0.5〜1

1〜∞

1〜2

2〜∞
に分割したのと同じです。
これを繰り返せば数直線を無限に分割できます。
Stern-Brocot 木の木構造としての性質等は
Spaghetti Source - Stern-Brocot 木
http://www.prefield.com/algorithm/math/stern_brocot_tree.html

を参照してください。
さてStern-Brocot木を2分探索してゆけば全ての少数を分数に変換できるのですが、
そのためにはStern-Brocot木を前もって作成しておく必要はありません。
与えられた少数と分割点とを比較しながら片側の子のみを辿ってゆけばよい。

この辺はコードにしたほうがわかりやすい。




実行結果

245850922 % 78256779


0 件のコメント:

コメントを投稿

Haskell Process

Haskellの System.Processは便利ですが、問題もあります。 単一スレッドでの逐次処理を保証していない。(想像です。) 次のようなスクリプトを書いてみた。 --a.hs main = print [1..10] --t.hs import Sy...