数と遊ぼう

多くのプログラミング言語、特に「実用的」な言語には、 xkcd でネタにされているように、数の扱いについておかしなコーナーケースがあったり一貫性が欠けていたりします。

このことは、数値用の演算子を数値でないものまで拡大解釈 (+ を文字列の連結とみなすような) して使用したり、数値と文字列との間で自動変換を行ったりすることにつながります。Frege では (Haskell もそうですが) 型が混在していると演算子が使えないため、このような問題は起こりえません。

型について問題は起こらない
 1  +  1  -- Int plus
 1  + "1" -- Type error: "String is not an instance of Num"
"1" + []  -- Type error

しかしながら、実際のコンパイル時には、ある種の高度な推論が行われてプログラマに楽をさせてくれます。もともと型システムは、次のような式を許可しないはずです。

1 + 1.0

というのも、1Int 型で 1.0Double 型ですが、+ は演算されるふたつの数が同じ型であることを要求するからです。

コンパイラはある程度賢いため、このような単純な数値リテラルの場合に 1.0 + 1.0 と書くことを強制することはありません。1 が登場する式の型に関する制約を解くことで、プログラマが何を意図したのかを推測してくれます。もう一つ、少しだけ発展的な例を見てみましょう。

型は何になる?
1 / 2

さっきと同じように 1 および 2Int 型の数値リテラルですが、Frege では除算の演算子は Int 型に対して (それ以外の Integral 型に対しても) 定義されてはいません。除算演算子は両方の被演算数が Real 型クラスに属する数値型であることを要求し、この場合 Frege では (Haskell と異なりデフォルトでは必ず) 具体型として Double が採用されます。つまり、次のようになります。

1 / 2 == 0.5  -- type is Double
Note
Java では 1 / 20 に評価されるため、挙動がまったく違います。

このことは面白い帰結をもたらします。というのも、Java の Double 型は数多くの特殊ケースをうまく処理しているからです。

Double のいいところ

もっともよくある特殊ケースはゼロによる除算です。Frege ではどのように扱われているのでしょうか?

ゼロによる除算
1 / 0  -- Infinity
Warning
数値の文字列表現は必ずしも数字のみからなるわけではないことに注意しましょう。小数点、マイナス記号や E の文字などは気付きやすいですが、InfinityNaN (これは数値ではない) のことを忘れがちです。

無限大を含む式を計算するとどうなるでしょう? 何かに無限大を足した結果はやはり無限大です。無限大どうしを足すこともできます。しかし除算は定義されません。

無限大を含む計算
(1/0) + 1     -- Infinity
(1/0) * 3     -- Infinity
(1/0) + (1/0) -- Infinity
(1/0) * (1/0) -- Infinity
(1/0) / (1/0) -- NaN

NaN とは別に Infinity が存在する利点は何でしょう? Infinity が式の中に存在しても、通常の演算が可能な数値に戻せる場合があります。

無限大による除算
1 / (1/0)   -- 0.0

うん、なかなか面白いですね。その他、数学的に微妙な例について見てみましょう。

微妙な例
0 / 0       -- NaN
(1/0) / 0   -- Infinity
0 ^ 0       -- 1

これは一見、数学における決まり事に反しているように見えます。

数学からの逸脱?

数学では、ゼロによる除算は定義されません。無限大による除算やゼロのゼロ乗も同様に未定義です。

しかしながら、コンピュータが計算しているのは近似値であり、実用上 の数値計算において最善を尽くしているにすぎません。Math.PIMath.E を扱う際も精度には限界があります。所詮、平方根も単なる近似値に過ぎません。

平方根の自乗
import frege.prelude.Math
Math.sqrt 2 * Math.sqrt 2  -- 2.0000000000000004

いずれにしても我々が扱える計算精度は有限であるため、ゼロ除算のような操作が行われた時、プログラムごと吹き飛んでしまわないよう、計算限界の範囲内でそれなりにうまく振る舞うように仕込みを入れておくのは悪いことではありません。

results matching ""

    No results matching ""