Smalltalk-72で遊ぶOOPの原点:「sqrt」を実装する(コードと解説編)

アラン・ケイの“メッセージングによるプログラミング”という着想に基づき(非同期処理などいろいろ足りていないながらも──)比較的忠実に実装された1970年代の非常に古いSmalltalk-72に実際に触れてみるシリーズ 第2弾です(なお最新のSmalltalkについては Pharo などでお楽しみください!)。

今回は謎言語「Smalltalk-71」で書かれたスペースウォー・ゲームSmalltalk-72に移植して動かすことを目指します。前回(2019年)を含む他の記事はこちらから→Smalltalk-72で遊ぶOOPの原点 | Advent Calendar 2023 - Qiita


sqrt アクションを定義する

これで準備が整いましたので sqrtニュートン法でサクッと実装してしまいましょう。

to sqrt x y z (
    0.0 > :x ? (error)
    0.0 = x ? (!0)
    "y _ 1.0 * x.
    "z _ 1.0e`8 * x.
    repeat (z > y - "y _ y - ((y * y) - x) / y * 2 ? (done)).
    x is float ? (!y)
    z > abs y - "x _ 1 * y + z ? (!x) !y)

まず、テンポラリ変数として x y z を冒頭で宣言します。

メッセージとして送られた数値(入力値)を x にフェッチしつつ負ならばエラー(0.0 > :x ⇒ (error))、ゼロなら 0 を返します(0.0 = x ⇒ (⇑0))。

次に入力値 x1.0 にかけることで(たとえ整数であった場合でも) float に変換し、y に代入します。Smalltalk-72 では代入も ☞y の返値であるアトム(シンボルの実体)へのメッセージ ← 1.0 * x の送信です。

z には許容する誤差として、さしあたり入力値の 108 分の1くらいにしました。

あとは yy - (y^2 - x) / 2y の差の絶対値(前回定義した absアクションを使用)が z より小さくなるまで繰り返せば平方根が求まります(repeat (z > y - ☞y ← y - ((y * y) - x) / y * 2 ⇒ (done)).)。

注意する点は、まず、演算が右結合なので必要なら括弧を適切に使用することです。乗除優先でないことを意識して括弧を用いる点は Smalltalk-80 でも同じですが、右結合か左結合かの違いがあるので、Smalltalkをよく知ってる場合でも要注意です^^;

そして、浮動小数点数と整数との演算で浮動小数点数を返したいときは、整数がレシーバーにならないようにする(交換則が成り立つならメッセージ側に移動、もしくは、今回は該当しませんがそうできない場合は -アクションのように、あらかじめ整数を 0.0 に足したり 1.0 にかけるなどして浮動小数点数に変換しておく)ことです。

最後は、送られてきた数値が float なら結果をそのまま返し(x is float ⇒ (⇑y))、結果が整数に近い値なら整数として返す(z > abs y - ☞x ← 1 * y + z ⇒ (⇑x) ⇑y)という余計で汚い処理(^^;)を付け加えています。

「spaceship」を解析するへ続く)