Below you find a considerable number of words for dealing with
divisions. A major difference between them is in dealing with signed
division: Do the words support signed division (those with the
U
prefix do not)?
If they do, do they round towards negative infinity (floored division,
suffix F
), or towards 0 (symmetric division, suffix S
).
The standard leaves the issue implementation-defined for most standard
words (/ mod /mod */ */mod m*/
), and different systems have
made different choices. Gforth implements these words as floored
(since Gforth 0.7). There is only a difference between floored and
symmetric division if the dividend and the divisor have different
signs, and the dividend is not a multiple of the divisor. The
following table illustrates the results:
floored symmetric dividend divisor remainder quotient remainder quotient 10 7 3 1 3 1 -10 7 4 -2 -3 -1 10 -7 -4 -2 3 -1 -10 -7 -3 1 -3 1
The common case where floored vs. symmetric makes a difference is when dividends n1 with varying sign are divided by the same positive divisor n2; in that case you usually want floored division, because then the remainder is always positive and does not change sign depending on the dividend; also, with floored division, the quotient always increases by 1 when n1 increases by n2, while with symmetric division there is no increase in the quotient for -n2<n1<n2 (the quotient is 0 in this range).
In any case, if you divide numbers where floored vs. symmetric makes a
difference, you should think about which variant is the right one for
you, and then use either the appropriately suffixed Gforth words, or
the standard words fm/mod
or sm/rem
.
Single-by-single-cell division:
/
( 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 is the modulus of n1/n2
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*n4+n3; n3 is the modulus, n4 the quotient.
/mods
( n1 n2 – n3 n4 ) gforth-1.0 “slash-mod-s”
n3 is the remainder, n4 the quotient
/modf
( n1 n2 – n3 n4 ) gforth-1.0 “slash-mod-f”
n3 is the modulus, n4 the quotient
u/mod
( u1 u2 – u3 u4 ) gforth-1.0 “u-slash-mod”
u3 is the modulus, u4 the quotient
Double-by-single-cell division with single-cell results; these words are roughly as fast as the words above on some architectures (e.g., AMD64), but much slower on others (e.g., an order of magnitude on various Aarch64 CPUs).
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 style mixed division
*/
( ( n1 n2 n3 – n4 ) core “star-slash”
n4=(n1*n2)/n3, with the intermediate result being double
*/s
( n1 n2 n3 – n4 ) gforth-1.0 “star-slash-s”
n4=(n1*n2)/n3, with the intermediate result being double
*/f
( n1 n2 n3 – n4 ) gforth-1.0 “star-slash-f”
n4=(n1*n2)/n3, with the intermediate result being double
u*/
( u1 u2 u3 – u4 ) gforth-1.0 “u-star-slash”
u4=(u1*u2)/u3, with the intermediate result being double.
*/mod
( n1 n2 n3 – n4 n5 ) core “star-slash-mod”
n1*n2=n3*n5+n4, with the intermediate result (n1*n2) being double; n4 is the modulus, n5 the quotient.
*/mods
( n1 n2 n3 – n4 n5 ) gforth-1.0 “star-slash-mod-s”
n1*n2=n3*n5+n4, with the intermediate result (n1*n2) being double; n4 is the remainder, n5 the quotient
*/modf
( n1 n2 n3 – n4 n5 ) gforth-1.0 “star-slash-mod-f”
n1*n2=n3*n5+n4, with the intermediate result (n1*n2) being double; n4 is the modulus, n5 the quotient
u*/mod
( u1 u2 u3 – u4 u5 ) gforth-1.0 “u-star-slash-mod”
u1*u2=u3*u5+u4, with the intermediate result (u1*u2) being double.
Division with double-cell results; these words are much slower than the words above.
ud/mod
( ud1 u2 – urem udquot ) gforth-0.2 “ud/mod”
divide unsigned double ud1 by u2, resulting in a unsigned double quotient udquot and a single remainder urem.
m*/
( d1 n2 u3 – dquot ) double “m-star-slash”
dquot=(d1*n2)/u3, with the intermediate result being triple-precision. In ANS Forth u3 can only be a positive signed number.
You can use the following environmental query floored
(see Environmental Queries) to learn whether / mod /mod */
*/mod m*/
use floored or symmetric division.
One other aspect of the integer division words is that most of them
can overflow, and division by zero is mathematically undefined. What
happens if you hit one of these conditions depends on the engine, the
hardware, and the operating system: The engine gforth
tries
hard to throw the appropriate error -10 (Division by zero) or -11
(Result out of range), but on some platforms throws -55
(Floating-point unidentified fault). The engine gforth-fast
may produce an inappropriate throw code (and error message), or may
produce no error, just produce a bogus value. I.e., you should not
bet on such conditions being thrown, but for quicker debugging
gforth
catches more and produces more accurate errors than
gforth-fast
.