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 LOOP 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.