3.26 Floating Point

Floating-point (FP) numbers and arithmetic in Forth works mostly as one might expect, but there are a few things worth noting:

The first point is not specific to Forth, but so important and yet not universally known that I mention it here: FP numbers are not reals. Many properties (e.g., arithmetic laws) that reals have and that one expects of all kinds of numbers do not hold for FP numbers. If you want to use FP computations, you should learn about their problems and how to avoid them; a good starting point is David Goldberg, What Every Computer Scientist Should Know About Floating-Point Arithmetic, ACM Computing Surveys 23(1):5−48, March 1991.

In Forth source code literal FP numbers need an exponent, e.g., 1e0; this can also be written shorter as 1e, longer as +1.0e+0, and many variations in between. The reason for this is that, for historical reasons, Forth interprets a decimal point alone (e.g., 1.) as indicating a double-cell integer. Examples:

2e 2e f+ f.

Another requirement for literal FP numbers is that the current base is decimal; with a hex base 1e is interpreted as an integer.

Forth has a separate stack for FP numbers in conformance with Forth-2012. One advantage of this model is that cells are not in the way when accessing FP values, and vice versa. Forth has a set of words for manipulating the FP stack: fdup fswap fdrop fover frot and (non-standard) fnip ftuck fpick.

FP arithmetic words are prefixed with F. There is the usual set f+ f- f* f/ f** fnegate as well as a number of words for other functions, e.g., fsqrt fsin fln fmin. One word that you might expect is f=; but f= is non-standard, because FP computation results are usually inaccurate, so exact comparison is usually a mistake, and one should use approximate comparison. Unfortunately, f~, the standard word for that purpose, is not well designed, so Gforth provides f~abs and f~rel as well.

And of course there are words for accessing FP numbers in memory (f@ f!), and for address arithmetic (floats float+ faligned). There are also variants of these words with an sf and df prefix for accessing IEEE format single-precision and double-precision numbers in memory; their main purpose is for accessing external FP data (e.g., that has been read from or will be written to a file).

Here is an example of a dot-product word and its use:

: v* ( f_addr1 nstride1 f_addr2 nstride2 ucount -- r )
  >r swap 2swap swap 0e r> 0 ?DO
    dup f@ over + 2swap dup f@ f* f+ over + 2swap
  2drop 2drop ;

create v 1.23e f, 4.56e f, 7.89e f,

v 1 floats  v 1 floats  3  v* f.

Assignment: Write a program to solve a quadratic equation. Then read Henry G. Baker, You Could Learn a Lot from a Quadratic, ACM SIGPLAN Notices, 33(1):30−39, January 1998, and see if you can improve your program. Finally, find a test case where the original and the improved version produce different results.

Reference: Floating Point; Floating point stack; Number Conversion; Memory Access; Address arithmetic.