Reasoned Schemer (100) わり算 続き3
/o
自体は問題ない
(defrel (/o n m q r)
(conde
((== '() q) (== r n) (<o n m))
((== '(1) q) (=lo m n) (+o r m n) (<o r m))
((poso q) (<lo m n) (<o r m) (n-wider-than-mo n m q r))))
n-wider-than-mo
は数式と見比べつつ読んでいきたい
n-wider-than-mo
っていうのは何をするか、じゃなくて
n
がm
よりも長いとき(のわり算)ってことなんだな
今ごろ納得した
(defrel (n-wider-than-mo n m q r)
これはn = m*q + r
に対応
(fresh (nhigh nlow qhigh qlow)
(fresh (mqlow mrqlow rr rhigh)
fresh
を2回に分けているのはどういうことか
1行にまとめても動きは変わらないっぽい
本の横幅の都合上かな?それだけ?
(splito n r nlow nhigh)
(splito q r qlow qhigh)
p
をr
の長さ+1とするとこれは
n = nhigh*2^p + nlow
q = qhigh*2^p + qlow
に対応
次はconde
に入って
(conde
((== '() nhigh)
(== '() qhigh)
(-o nlow r mqlow)
(*o m qlow mqlow))
これは基底ケースになっているのかな
(相互に再帰してるので基底ケースは/o
にもある)
nhigh=0
でqhigh=0
だからn = nlow
でq = qlow
nlow - r = m*qlow
となるnlow
、r
、m
、qlow
を探す
r
<m
であることは/o
内で指定済みなのでいいとして
これはここで上限なしの再帰に入らない保証があるの?
((poso nhigh)
(*o m qlow mqlow)
(+o r mqlow mrqlow)
(-o mrqlow nlow rr)
(splito rr r '() rhigh)
(/o nhigh m qhigh rhigh))))))
nhigh
が0でない
m*qlow + r - nlow
をr
でsplito
して()
とrhigh
にする
(splito rr r '() rhigh)
はrhigh*2^p = m*qlow + r - nlow
に対応
そういうn
やらm
やらq
やらr
があることを確認してから
(/o nhigh m qhigh rhigh))
を計算する
ここが数式で説明のあったところだな
ここで再帰する
nhigh
をm
で割ってみる、ってのはこのことか
いくらか問題が小さくなってることは間違いないのでいつか止まるってことだろう
q = qhigh*2^p + qlow
で出てくるqhigh
と
nhigh = m*qhigh + rhigh
に出てくるqhigh
は(当然ながら)同じもので、
そうするとrhigh
は決まってしまうけれども
そのrhigh
は(splito rr r '() rhigh)
を満たさなければならない
そうすると無限にいろんな値を試し続けることはなくなる、ということだね
わかってないけど
ここでnhigh
だとかが決まれば残りも芋づるで決まる、と
式との対応はついたがさて
何がいいかっていうと、最後のふたつの方程式をチェックするとき、
nlow
もqlow
もみんな範囲が制限されててpビットに収まってるってこと
(splito n r nlow nhigh)
で(splito q r qlow qhigh)
で
((== '() nhigh)
で(== '() qhigh)
だと
nlow
やqlow
の長さはせいぜいr
の長さ+1で、
そういう範囲に制限されてから(-o nlow r mqlow)
が評価されて
(だからmrqlow
の長さも制限されて)
そのあと(*o m qlow mqlow)
が評価されるから止まる
とか
(splito n r nlow nhigh)
で(splito q r qlow qhigh)
だから
nlow
やqlow
の長さはせいぜいr
の長さ+1で、
rhigh
も条件を満たすから(/o nhigh m qhigh rhigh)
も止まるであろうと
うーん、ここまでかな
頭よすぎる人の考えることはわからない