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


5.5.4 Integer division

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       “slash-s”
/f       n1 n2 – n        gforth       “slash-f”
u/       u1 u2 – u        gforth       “u-slash”
mod       n1 n2 – n         core       “mod”

n is the modulus of n1/n2

mods       n1 n2 – n        gforth       “mod-s”
modf       n1 n2 – n        gforth       “modf”
umod       u1 u2 – u        gforth       “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       “slash-mod-s”

n3 is the remainder, n4 the quotient

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

n3 is the modulus, n4 the quotient

u/mod       u1 u2 – u3 u4        gforth       “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       “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       “star-slash-s”

n4=(n1*n2)/n3, with the intermediate result being double

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

n4=(n1*n2)/n3, with the intermediate result being double

u*/       u1 u2 u3 – u4        gforth       “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       “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       “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       “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       “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 to learn whether / mod /mod */ */mod m*/ use floored or symmetric division.

FLOORED       – f         environment       “FLOORED”

True if / etc. perform floored 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.


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