固定小数点計算
【以下【】の中は訳者が付け足したものです。】
このマニュアルで用いてきたバージョンのMopsでは、 浮動小数点計算ではなく、 固定小数点計算(整数計算とも呼ばれます)を用いています。 これらの主な違いは、固定小数点計算は整数についてしか機能しないということです。 レッスン 3で割り算について実験したときにお気づきと思います。:スタック上の答えは商か、商と余り(どちらにしても整数)のどちらかでした。他方、浮動小数点計算は小数点より右側の数字を入力することができます。
浮動小数点計算は多くの場合に便利であって、特に、演算の結果が伝統的にきっちり割り切れる数ではないときにはそうです:例えば、 財務計算では小数点の右側にセントが表示されます。【日本では、利息計算、とか?】 しかし、浮動小数点には欠点もまたいくつかあります。これは、Mopsプログラマーとしては特に重要なことでしょう。
欠点の一つは、浮動小数点計算はコンピュータ内でメモリーサイズを整数より多く必要とするので、Mopsカーネルのサイズが大きくなるということです。これは、メモリーが今よりもずっと高価だった何年か前と比べれば、問題ではなくなりました。
第二に、浮動小数点計算は、普通は固定小数点計算よりも時間がかかります。 コンピューターや言語によっては、浮動小数点計算には、固定小数点計算で同じ計算を実行する場合よりも、10倍(場合によっては100倍も)の長い時間がかかることもあり得ます。
第三に、浮動小数点計算は、ある種の計算においては、固定小数点計算よりも正確さの点で劣ります。 例えば、浮動小数点計算では、ある数を正確に3分の1倍することはできません。;それには0.3333 ......をかけなければなりません。 そして、その種の計算には何らかの誤差はいつも伴います。 この3分の1の近似値に基づいてさらに計算を続けた後には、その誤差が膨らんでしまうこともあり得ます。
実際、大部分のプログラムは浮動小数点計算を全く必要としません。 この理由のため、基礎的なMopsシステムは、より小さく高速な固定小数点計算だけをサポートしており、 浮動小数点計算は、それを必要とする人のためのオプションとして利用可能なものとしています。
しかし、固定小数点計算にもそれ自体の問題はあります。あなたがπ(パイ)やパーセンテージのような整数ではない数の扱いに慣れているかもしれないからです。 そのような数を扱うには、Mopsではスカラーあるいは浮動小数点数を固定小数点数に変換するように見える演算を使う必要があります。
もっともよく使われる二つのスカラーは、実際にはよく使われる算術演算を結合した特別な例です。
*/ |
( n1 n2 n3 -- result ) |
‘n1’を‘n2’倍し、その答えを‘n3’で割った答えをスタックに残します。 |
*/MOD |
( n1 n2 n3 -- remainder result ) |
*/ と計算は同じですが、商と余りがスタックに残ります。 |
スタック上のアイテムの順序と、算術演算がそれらをどのように取り扱うのかについてよく注意してください。 というのは、これらは、Mopsの算術演算を結合する標準的やり方から予想できるものとは異なっているからです。 しかし、この順序のおかげで、問題の代数的な演算中置(infix)記法からMopsの演算後置記法に変換するに際して、プロセスがよりよく目に見えるものになっています。例えば、分数3分の2を100倍するための、紙と鉛筆による場合の式は、
100 * 2 / 3
ですが、これは、
100 2 3 */
となります。
同じような演算は、パーセンテージを計算するのにも利用できます。単に上のスタック
コメントの‘n3’のところに100をおき、パーセンテージの数字を‘n2’にあたるところにおけば良いのです。
Decimal(10進), Hex(16進)およびBinary(2進)計算
Mopsが"内部的に"数値を扱うときには、伝統的な10進法(基数が10)システム以外の数値システムがしばしば用いられています。 非10進法で最も良く使われている二つの数システムは16進法と2進法システムです。それぞれ全く異なる特性をもっています。
16進法(hexadecimal)システムは、基数が16のシステムです。 つまり、ひと桁から二桁に増えるのが、"1"の位が0から9を経て一巡したときではなくて、 15を過ぎたときに一巡するということです。 10進法での10は16進法ではAになります。; 10進法での11は16進法ではBです。;という具合に16進法はF まで続きます。 16進数(ときどき略して"hex"ともいいますが)は、普通は特殊記号である"$"が頭に付けられます。ですから$ 24は16進数での24(10進法では36)であって、10進法の24ではないとわかるのです。
2進法(binary)システムは、反対の極にあるもので、零と一の二つの数字しか持ちません。 この数システムは10進法や16進法と比べると、あまり便利には見えません 。しかし、Macでのプログラミングにさらに深く入り込めば、カーソルやテキストフォントやアイコンのような要素をデザインするのを容易にするには、二進数学が全く本質的であることに幾度となく気付かされるでしょう。
これらの基数の違いを明らかにするため、各基数について、最初の20までの数字を表にしました。:
Decimal(10進) |
Hexadecimal(16進) |
Binary(2進) |
0 |
0 |
0000 0000 |
1 |
1 |
0000 0001 |
2 |
2 |
0000 0010 |
3 |
3 |
0000 0011 |
4 |
4 |
0000 0100 |
5 |
5 |
0000 0101 |
6 |
6 |
0000 0110 |
7 |
7 |
0000 0111 |
8 |
8 |
0000 1000 |
9 |
9 |
0000 1001 |
10 |
A |
0000 1010 |
11 |
B |
0000 1011 |
12 |
C |
0000 1100 |
13 |
D |
0000 1101 |
14 |
E |
0000 1110 |
15 |
F |
0000 1111 |
16 |
10 |
0001 0000 |
17 |
11 |
0001 0001 |
18 |
12 |
0001 0010 |
19 |
13 |
0001 0011 |
20 |
14 |
0001 0100 |
このリストを見て、2進法と16進法の間に特別な関係があることに気付いたかも知れません。; 16進数のどこかの桁が最大値(F)に到達する度毎に、2進数の連続する四つの桁がその最大値(1111)に到達しています。この関係は見た目より重要なことが後でわかるでしょう。
上のリストに示された2進数は8ビット幅(2進法の各桁、つまり、0または1のある場所はビットと呼ばれます)ですが、Mopsは実際にはスタック上に数値を32ビット数【または、64ビット数】として格納します。 ですから、スタックに数値10(10進数で)を格納しても実際には数値は、
0000 0000 0000 0000 0000 0000 0000 1010
として格納されます。32ビット数の範囲内で何種類の数が記述できるのかを計算すれば、 4294967296個であることがわかるでしょう。40億を超えています。 あなたのMacにさせる大概の仕事には十分なほど大きな数値です。
注意:4ビットグループ毎に隙間を空けたことにお気づきでしょう。コンピューターのメモリーにはビットは一つ一つ並んで入っているのですが、読みやすさのためにこの規約を用いました。例えば 、10000010110001000000 は10000101100001000000と同じ数値でしょうか?4ビット毎にグループ分けして書けば、抵抗を感じることなく、あるいは、ひと桁ひと桁見比べることなく、これらは違う数値であることが容易にわかるでしょう。
しかし、これは40億の正の数です。負の数はどうなのでしょう?
符号付きおよび符号無し数
その答えは、40億の符号無し(unsigned)数(整数のみ)を、それぞれが20億ちょっとの二つの部分にわける、Mopsの特別なテクニックの中にあります。 一方の半分は正の領域に割り当てられ、他方は負の領域に割り当てられます。 言い換えると、これらの符号付き(正または負)数の領域は、プラスまたはマイナス2147483647です。
符号付き数の符号無し数と違うところは、その上に演算を実行するときのやり方です。 例えば、スタックに負の数を入力する場合には、マイナス記号(-)を付けることで、 符号付き数を用いようとしていることをMopsに知らせます。 他方、30億の数値をスタックに入力したならば、符号無し数を用いようとしていることをMopsは理解するでしょう。 なぜなら、プラスマイナス20億の範囲を超えるものは皆、符号無し数でしかあり得ないからです。
しかし、そうしたいならば、結果を強制して、スタック演算や表示の目的のためにスタック上の数値の意味を変更することができます。
このプロセスを理解するため、二進法でカウントするデジタルテープカウンターを持ったテープレコーダーを使っている場面を想像してください。 カウンターを0000 0000にセットして、テープの巻き戻しを始めたとします。最初にカウンターに見えるのは1111 1111です。これは実は、ゼロに対しては-1に当たるのです。 しかし、早送りをする場合のカウンターの最大数もまた1111 1111です。 その大きい方の数値が符号無し数の40億に対応するわけです。 しかし、符号付き数としては1111 1111はゼロから逆に数えて最初の数字、つまり-1を表しているのです。
この概念を実地で経験するため、まず、あなたがこのマニュアルの前の方の節で習得した.(ドット)コマンドは、 実際にはスタック上の数値の符号付きの等価物を表示する命令であったことを考えてください。 これは、プラスマイナス20億の範囲内の数値しか表示できないということを意味しています。 これを証明するために今30億の数値(3の後にゼロが9個)をスタックに入力しましょう。 きっと、スタックディスプレイは次のように見えるでしょう【32ビットバージョンの場合に限ります】。:
Stack: depth 1
-1294967296
これは符号付きの場合の等価物であって、負の10億付近の数値です。
逆に、-1(符号付き数)をスタックに入力してください。 今度は、それを符号無し数として表示したいわけです。 これをするためにはワードU.を用います。 これはまず数値を符号無し数に変換して、それからスクリーンにそれを打ち出します。
U. |
( n -- ) |
スタックのトップにある数値を、符号無し単精度数としてスクリーンに印字します。 |
U< |
( u1 u2 -- boolean ) |
二つの符号無し単精度数を比較します。 ‘u1’が‘u2’より小さいならば、 スタックにTRUEを残します。; そうでない場合は、FALSEを残します。 |
U> |
( u1 u2 -- boolean ) |
二つの符号無し単精度数を比較します。 ‘u1’が‘u2’より大きいならば、 スタックにTRUEを残します。; そうでない場合は、FALSEを残します。 |
次のコードを試して、何が起るか観察してください:
-1 U. cr
4294967295
|
違いを強調するために、-1を同じように、今度はU.ではなくて.を使って試してください。
数値セットの最後の例;ASCII
ASCIIコードと呼ばれる数値の集合は、既に見たことがあります。 これらの数値は、全ての数字、アルファベット文字、コンピューターキーボード上の記号、および、 コンピューター同士やコンピュータが利用する(プリンターのような)周辺機器との間の通信に用いられる数多くの制御コードに対して産業標準化グループによって割り当てられたものです。 ASCII("アスキー(as-key)"と発音します)は American Standard Code for Information Interchange(情報交換のための米国標準コード)の頭文字です。 この標準のおかげで、コンピューターは電話回線やネットワーク接続を通しても現在のように効果的に通信できるようになっているのです。
注意:実際には、Mopsそれ自身はユニコード(Unicode)をサポートしています。 これはずっと大規模な標準で、世界中の多くの言語を包含する他、それらの言語をコード化し、操作し、表示する形式的規則を含んでいます。 うまいことには、一般にはあなたはこの違いについて意識する必要はありません。 というのはASCIIの全ての文字はユニコード標準の部分集合として含まれているからです。 このマニュアルでは、"ASCII"という語を、"ユニコード標準の部分集合で、ASCII文字集合にある文字で構成されたもの"という意味で用います。
【とはいうものの、PowerMopsにおけるユニコード利用はMac OSの機能を経由した最小限のもので、
システムコールを利用して完全に対応することはできますが、デフォルトでフルサポートとはいえません。(私見)】
キーボード上で‘a’を押すと、コンピューターは、その文字を97(10進法)としてのみ認識します。各文字及び記号は固有の数値を持っているので、押されたキーを比較し、あなたが既に学んだたくさんの数値処理ツールでスクリーン上の文字を操作することができるのです。 例えば、アルファベットの大文字は全て65から90までの番号が振られていることを知っていれば、 それらの文字を直ちにスクリーン上に印字するDO ... LOOPを作ることが可能です。:
: ALPHABET 91 65 DO i emit cr LOOP ;
EMITはASCII番号で参照された文字をスクリーン上に表示するMopsワードです。 特定のASCII文字の値をスタック上に置きたいときは、Mopsワード"&"(ampersand【アンド記号】)が利用できます。 次のように打ち込んでみてください。:
& c . cr
99
|
スタックディスプレイに99が表示されるのを見ることもできるでしょう。これが、‘c’のASCII値です。 EMITや&と並んで使われるであろうMopsワードには次のようなものがあります。:
EMIT |
( n -- ) |
ASCII番号‘n’で参照される文字を表示します。 |
SPACE |
( -- ) |
スクリーン上に半角空白を表示します。 |
SPACES |
( n -- ) |
スクリーン上に‘n’個の半角空白を表示します。 |
次のSPACESを用いた修正版ALPHABETで、その威力を目の当りにしていただきましょう。:
: ALPHABET2 91 65 DO i dup 64 - spaces emit cr LOOP ;
大文字と小文字は、どの文字かによらず、32だけ離れていることを覚えておくと便利でしょう。 これは大文字を小文字に変換したり、その逆をしたりする必要があるときに役に立つでしょう。
最終更新:2018年12月09日 20:30