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.
Do signed division words 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*/
). Gforth
implements these words as floored (since Gforth 0.7), but there are
systems that implement them as symmetric. 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
.
In the following, “remainder” (symmetric) has the same sign as the dividend or is 0, while “modulus” (floored) has the same sign as the divisor or is 0.
The following words perform 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”
n1=n2*n4+n3; n3 is the remainder, n4 the quotient
/modf
( n1 n2 – n3 n4 ) gforth-1.0 “slash-mod-f”
n1=n2*n4+n3; n3 is the modulus, n4 the quotient
u/mod
( u1 u2 – u3 u4 ) gforth-1.0 “u-slash-mod”
u1=u2*u4+u3; u3 is the modulus, u4 the quotient
The following words perform 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 ARM A64 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.
The following words perform 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 Forth-2012 u3 is only allowed to be a positive signed number.
You can use the environmental query floored
(see Environmental Queries) to learn whether / mod /mod */
*/mod m*/
use floored or symmetric division on the system your
program is being loaded on; alternatively, -1 3 /
also produces
-1 on floored and 0 on symmetric systems.
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
.