後で見直したら、ネタかぶってましたね(^^;;)。すみません。 ここの記事は、ちょっとMops/Forthから離れた、一般論からの補遺って感じでご理解お願いします。
ぶっちゃけていえば、マイナスの数も使うかどうかです。普通の英語の意味で、ここでいっているsignというのはプラス/マイナスの符号のことで、signedは符号がつく、unsignedは符号がつかないです。まあ、プラスだって+符号がつくじゃないかと突っ込めますが、省略するでしょ、普通。それと、コンピュータでは、マイナスがつかない数字は数値リテラルといって、文字通りのその数値を意味するものとして考えられているわけで、それは当然、正か0の値を意味すると考えるわけですね。つまり、マイナスは特別につける記号なわけです。で、signedは、マイナスの記号がつく、つまり、負の数も考えるということなわけです。まわりくどいな。
だからといって、コンピュータがマイナス符号を理解するわけじゃない、というのは、前にも書きました。まあ、負の数かどうかを示す指標はあるんですが。負の数の表現としては、足し算するとちょうど桁が溢れて全部が0になる数の組があるわけで、それらは当然互いに逆元関係にあると見ていいわけです。ええと、逆元というのは、まあ、ここでは足すと0になる数ということですね。かけ算の逆元は、掛けると1になる数ですね。一般論はやめときます。
この体系でいくと、計算は、負の数かどうかというのを考えずに計算できるわけです。ただ、符号なし、つまり、0か正の数と解釈するときには、桁が溢れると数値が不正確になる、というに過ぎません。でてきた結果の解釈だけで済むわけです。つまり、符号付かどうかというのは、中身には関係ないのです。
1バイトを2進(ビット)表示して1000 0000の場合、符号付だと値は-128、符号なしだと128です。27の桁が1なわけで、これが128ということです。0111 1111だと符号付だろうがなんだろうが127です。127に1足せば、ちょうど1000 0000のような表現になるのですから、符号付でもそれを128にしてもいいような気もしますが、符号付数の中の"符号なし"にあたる部分が0~127で128個あるので、これはマイナスにしておいた方がバランスはいいですね(つまり、負の数は-128~-1の128個の数値で符号ありと無しが半々になる)。それに、"頭の桁が1なら負"というのはわかりやすい指標になりますからね。符号なしにすると、大きい数が、大体2倍まで使えるわけです。きっちり2倍じゃないですけどね。2倍より1こ多いですね。0から始まるんで、最大数はみな奇数になるんですね。
少し硬い言い方をすると、溢れた桁を捨てることで、コンピュータ内の整数値は有限環になるわけで、例えば1バイト数なら、256(符号なし数で)=0で循環する数ということになります。"256を法(modulus)とする"といいますね。ひもの端を0と256と考えて輪を作った状態でイメージできます。まあ、整数はとびとびなので、円よりも256角形のほうがいいですかね。0から反時計回りで数値を割り振って、0と(-)128を結べば、ちょうど半分に分ける対角線ですね。で、この軸に直交する対角線で結びつく数値は、符号付き数と見れば互いに加法逆元、符号なし数と見れば256ですね。前は「中心通る対角線が逆元」とか書いてましたけど、全然違いますね。テキトーですみません。ともあれ、こうすることで、有限アーベル群、というか有限可換群構造が入るわけです。まあ、硬い話はこの辺でやめましょう。
とまあ、符号なし数か符号付き数かは実体に関係ない、といえるのは、実は、0-1表現だけで考えているなら、という条件の下だけです。つまり、これを型として考えると、解釈の一貫性をどうやってつけるかも問題になります。前にも書いたように、型というのは値の"意味"なわけですから、当然解釈も伴っているわけです。符号なし数同士、あるいは、符号付き数同士、の計算なら、それぞれ結果も、符号なし/符号付きと解釈していいでしょう。じゃあ、混ぜたときはどうするんでしょう。
これは、例えばC言語などでは、型の優先順位(preference)というのを考えます。計算結果の型は、「より大きい」型に揃えられるわけです。符号付きと符号なしでは、符号なしが「大きい」ようで、バイト幅が同じの、符号なしと符号付きを計算すると、結果は符号なし型になるらしいです(本にそう書いてあるんですが、じゃあ、32ビットの、符号付き-2と符号なし1を足すと、42億9496万7295になるんですかね。すみません、あやふやで。その辺はCの教科書でもみてください。MopsやForthでは、関係ないネタなわけですから、コンピュータ科学の一般論にはならないってことですよね。)。ただ、この優先順位は、バイト幅の違いも加わって複雑怪奇になる危険がありまして、実際、同じ言語でもコンパイラによって違うものらしいです(つまり、C言語の教科書より、開発環境のマニュアルに頼らないといけないということですね。)。もっとも、バイト幅さえ大きくとって桁がはみ出さない(情報が損なわれない)ようにしておきさえすれば、"普通の"プログラミング言語では計算結果も結局は型が宣言された変数に格納されるので、その格納される変数の型に合わせてしまえばいいわけで、大きな問題にはならないわけです(多分^^;;)。
Mops/Forthでは、こういうやかましいことは全く問題になりません。解釈が必要になったそのつど解釈するからです。変数に入れるには意味付けが必要であるような、静的に型付られた言語との違いです。ただ、符号付きか符号なしかが問題になる局面はあり得ます。例えば大小を比較するときです。マイナスの数というのは、符号なしの数に解釈すると、ものすごく大きな数になってしまうからです。逆に、符号なし数として考えているのに、符号付きに解釈されてしまうと、相当大きな数が0より小さいことにされてしまいます。
Mops/Forthでは、符号なし数として大小を比較するワードを特別に準備することで対応しています。ついでですので、どんなワードか見ておきましょう。
標準は、符号付き数としての比較で、">"、"<"などのような、おなじみの記号(実際はワード名ですが)をつかいます。詳しい使い方はここでは書きませんが、スタック上の二つの数値を比較して、真偽値をスタックに残すことになります。
符号なし数として比較するときには、"U>"、"U<"のように、Uをつけます。unsignedのuですね、多分。
符号付き云々が問題になるのは、少なくとも頭の桁が1になるくらいの絶対値の大きな数だけです。ですから、大抵、これを問題にするのはビット数が小さい1バイト数の場合です。型としてみれば、文字列の文字数とか、負にはなり得ないものは符号なしが当然です。大きな値で符号なしで使っている例としては、メモリーのアドレスがあります。大きいですからね、昨今のメモリーは。32ビットだと4GBまでということです。64ビットコンピュータが云々される最大の理由は、巨大なメモリーのアドレスを簡便に扱いたいから、ということだと思いますね。何台もつないだときにですね。
Mops/Forthでも、値が一定の解釈を要請するときには、それに応ずることができないといけません。特に、Mops/Forthでは、1セルより小さい幅のメモリに格納されている数も、スタック上の1セル(Mopsでは4バイト)に落としてから使います。このとき、符号を反映させるのかどうかを考えなければなりません。
この観点からいうと、Mops/Forthでは、バイト幅の小さいメモリー中の値は、"符号なし"として扱うのがデフォルトになっています。1バイト/2バイトのメモリーから値を取り出す標準ワードはそれぞれC@とW@ですが、これは、メモリー中の符号なしの数としてセル上に展開するからです。符号付と解釈するワードはC@XとW@Xで、後ろにXがつきます。これはextensionのXで、負号をスタックセル全体に拡張するという意味です。普通は空いた桁に0を詰め、拡張版では頭の桁に呼応して1をつめることもあるわけですね。
最終更新:2019年07月08日 15:05