Next: , Previous: , Up: Arithmetic   [Contents][Index]


6.5.4 Integer division

以下にあるように、 除算を扱うために相当な数のワードがあることが分かります。 これらの主な違いは、 符号付き除算の処理にあります。 これらのワードはどのようにして符号付き除算に対応するのでしょうか? (U プレフィックスが付いたワードでは符号付き除算に対応しません)

商を四捨五入して整数に丸める場合、 負の無限大に向かって丸めるのでしょうか(floored division(床除算)、 接尾辞 F)、 それとも 0 に向かって丸めるのでしょうか(symmetric division、接尾辞 S)。 標準では、 ほとんどの標準ワード(/ mod /mod */ */mod m*/)について、 問題なのは、 各々の実装依存のままであり、 システムごとに異なる選択が行われています。 Gforth では、こ​​れらのワードをfloorとして実装します(Gforth 0.7 以降)。 floored division と symmetric division の違いは、 割られる数と割る数の符号が異なり、 かつ、 割られる数が割る数の倍数で無い場合のみです。 以下の表に組み合わせの結果を示します:

                      floored          symmetric
割られる  割る数      余り 商            余り 商
    10      7           3   1              3   1
   -10      7           4  -2             -3  -1
    10     -7          -4  -2              3  -1
   -10     -7          -3   1             -3   1

floored と symmetric とが違いを生む一般的なケースは、 様々な符号の被除数(割られる数) n1 が、 同一の正の除数(割る数) n2 で除算される場合です。 同一の正の除数(割る数) n2 で除算される場合、 通常は floored division が必要で、なぜなら、 同一の正の除数(割る数) n2 で除算される場合、 余りは常に正となり、 被除数(割られる数)に応じて符号が変化しないからです。 また、 floored division では、 n1 が n2 増加すると商は常に 1 増加しますが、 symmetric division では、 -n2<n1<n2 の場合は商は増加しません(この範囲では商は 0 です)。

いずれの場合でも、 floored と symmetric とで違いが生ずる数値を除算する場合は、 どのバリエーションが適切であるかを考えてから、 適切な接尾辞を付けた Gforth ワードか、 標準ワードの fm/mod または sm/rem のいずれかを使用する必要があります。

1倍長セル同士の除算:

/ ( n1 n2 – n  ) core “slash”

n=n1/n2

/s ( n1 n2 – n ) gforth-1.0 “slash-s”
/f ( n1 n2 – n ) gforth-1.0 “slash-f”
u/ ( u1 u2 – u ) gforth-1.0 “u-slash”
mod ( n1 n2 – n  ) core “mod”

n は n1/n2 の余り(modulus)

mods ( n1 n2 – n ) gforth-1.0 “mod-s”
modf ( n1 n2 – n ) gforth-1.0 “modf”
umod ( u1 u2 – u ) gforth-1.0 “umod”
/mod ( n1 n2 – n3 n4  ) core “slash-mod”

n1/n2 を行い、 n3 が余り(modulus)、 n4 が商です(n1=n2*n4+n3)。

/mods ( n1 n2 – n3 n4 ) gforth-1.0 “slash-mod-s”

n3 が余り(remainder)、 n4 が商

/modf ( n1 n2 – n3 n4 ) gforth-1.0 “slash-mod-f”

n3 が余り(modulus)、 n4 が商

u/mod ( u1 u2 – u3 u4 ) gforth-1.0 “u-slash-mod”

u3 が余り(modulus)、 u4 が商

2倍長セルを1倍長セルで割って1倍長セルの結果を得る; これらのワードは、 一部のアーキテクチャ(AMD64 など)では上記ワードとほぼ同じ速度ですが、 他のアーキテクチャ(さまざまな Aarch64 CPU など)でははるかに遅くなります。

fm/mod ( d1 n1 – n2 n3 ) core “f-m-slash-mod”

Floored division: d1 = n3*n1+n2, n1>n2>=0 or 0>=n2>n1.

sm/rem ( d1 n1 – n2 n3 ) core “s-m-slash-rem”

Symmetric division: d1 = n3*n1+n2, sign(n2)=sign(d1) or 0.

um/mod ( ud u1 – u2 u3 ) core “u-m-slash-mod”

ud=u3*u1+u2, 0<=u2<u1

du/mod ( d u – n u1 ) gforth-1.0 “du-slash-mod”

d=n*u+u1, 0<=u1<u; PolyForth スタイルの混合除算

*/ ( ( n1 n2 n3 – n4  ) core “star-slash”

n4=(n1*n2)/n3 中間結果は2倍長

*/s ( n1 n2 n3 – n4 ) gforth-1.0 “star-slash-s”

n4=(n1*n2)/n3 中間結果は2倍長

*/f ( n1 n2 n3 – n4 ) gforth-1.0 “star-slash-f”

n4=(n1*n2)/n3 中間結果は2倍長

u*/ ( u1 u2 u3 – u4 ) gforth-1.0 “u-star-slash”

u4=(u1*u2)/u3 中間結果は2倍長

*/mod ( n1 n2 n3 – n4 n5  ) core “star-slash-mod”

n1*n2=n3*n5+n4 中間結果(n1*n2)は2倍長、 n4 は剰余、 n5 は商。

*/mods ( n1 n2 n3 – n4 n5 ) gforth-1.0 “star-slash-mod-s”

n1*n2=n3*n5+n4, 中間結果(n1*n2)は2倍長、 n4 は余り(remainder)、 n5 は商

*/modf ( n1 n2 n3 – n4 n5 ) gforth-1.0 “star-slash-mod-f”

n1*n2=n3*n5+n4 中間結果(n1*n2)は2倍長。 n4 余り(modulus)、n5 は商

u*/mod ( u1 u2 u3 – u4 u5 ) gforth-1.0 “u-star-slash-mod”

u1*u2=u3*u5+u4 中間結果(u1*u2)は2倍長。

除算結果を2倍長セル(double-cell)で得ます。 以下のワード群は上記のワード群よりもはるかに遅いです。

ud/mod ( ud1 u2 – urem udquot  ) gforth-0.2 “ud/mod”

符号無し2倍長 ud1u2 で割る。 結果は、符号なし2倍長の商 udquot と、 1倍長の余り(remainder) urem です。

m*/ ( d1 n2 u3 – dquot  ) double “m-star-slash”

dquot=(d1*n2)/u3, 中間結果は3倍長です。 ANS Forth では u3 は正の符号付き数値のみです。

環境クエリ(environmental query) floored を使用すると、 / mod /mod */ */mod m*/ が floored division か symmetric division かを確認できます(see Environmental Queries)。

整数除算ワードのもう 1 つの側面は、 整数除算ワードのほとんどがオーバーフローする可能性があり、 かつ、 ゼロによる除算が数学的に定義されていないことです。 これらの条件のいずれかに該当した場合に何が起こるかは、 エンジンやハードウェアやオペレーティング・システムによって異なります。 gforth エンジンは、適切なエラーである -10 (Division by zero;ゼロ除算) または -11 (Result out of range;範囲外の結果) を throw しようと懸命に試みます、 が、 しかし、 一部のプラットフォームでは -55(浮動小数点未確認エラー;Floating-point unidentified fault)が throw されます。 gforth-fast エンジンでは、 不適切な throw コード(およびエラー・メッセージ)を生成する場合や、 エラーを生成せずに嘘の値のみを生成する場合があります。 つまり、 あなたは、 そのような条件が throw されることに賭けるべきではありません。 そして、 あなたが迅速なデバッグを行うためには、 gforth エンジンは gforth-fast エンジンよりも多くのエラーをキャッチし、 より正確なエラーを生成します。


Next: Two-stage integer division, Previous: Mixed precision, Up: Arithmetic   [Contents][Index]