NDP Floating Point (Ext stack)

Introduction

Two of the three floating point packages use the FPU instruction set. The source code can be found in the files Lib\x64\Hfpx64.fth and Lib\x64\Ndpx64.fth.

Hfpx64.fth - external FP stack

In Hfpx64.fth floating point numbers are kept on a separate stack, pointed to by the USER variables FSP and FS0. The top of the FP stack is cached in the FPU. Register R13 (initialised from FS0) is the primary FP stack pointer.

All tasks, winprocs and callbacks are allocated a separate 4096 byte floating point stack. If you need a larger one, allocate it from the heap using ALLOCATE, and modify FSP and FS0 accordingly. Note that the stack grows down. )

Hfpx64.fth defines floating point stack items and literals to be in 80 bit extended real format in memory.

Ndpx64.fth - coprocessor stack

In Ndpx64.fth floating point numbers are kept in the floating point unit's internal stack only. This code is significantly faster, but is limited to the use of 8 floats on the NDP stack, including working temporary numbers.

Ndpx64.fth defines literal and default floats using F@ F! and friends to be in 80 bit format. Change the constant FPCELL as above to use a different default size.

Radians and Degrees

Please note that the trig functions are calculated in radians, for calculations in degrees use DEG>RAD beforehand, RAD>DEG afterwards.

Number formats, ANS and Forth200x

The ANS Forth standard specifies that floating point numbers must be entered in the form 1.234e5 and must contain a point '.' and 'e' or 'E', and that double integers are terminated by a point '.'.

This situation prevents the use of the standard conversion words in international applications because of the interchangable use of the '.' and ',' characters in numbers. Because of this, VFX Forth uses two system variables, FP-CHAR and DP-CHAR, to hold the character used as the floating point and double integer indicator characters. By default, FP-CHAR is initialised to '.' and DP-CHAR is initialised to ',', as has been MPE practice for many years. For ANS compliance, you should set them as follows:


\ ANS standard setting
  char . dp-char !
  char . fp-char !
: ans-floats    \ -- ; for strict ANS compliance
  [char] . dp-char !
  [char] . fp-char !
;
\ MPE defaults
  char , dp-char !
  char . dp-char 1+ c!
  char . fp-char !
: mpe-floats    \ -- ; for existing and most legacy code
  [char] , dp-char !
  [char] . dp-char 1+ c!
  [char] . fp-char !
;
\ Legacy defaults, including ProForth
  char , dp-char !
  char . fp-char !
: legacy-floats \ -- ; for legacy code
  [char] , dp-char !
  [char] . fp-char !
;

You can of course set these variables to any value which suits you for your language and locale. Note that integer conversion is always attempted before floating point conversion. This means that if FP-CHAR and DP-CHAR are the same, floating point numbers must contain 'e' or 'E'. If they are different, a number containg the FP-CHAR will be successfully converted as a floating point number, even if it does not contain 'e' or 'E'.

Floating point exceptions

Exception handling is determined by the operating system. On current Windows platforms, floating point exceptions are not generated by The NDP. This can be changed by altering the bottom 6 bits of the NDP control word using CW@ and CW!.

By default, the system prompt will report exception status, and clear the pending exception status. Exception status reporting does not mean that the Windows exception handler has been triggered, it only means that the status flag has been set.

Standards compliance, F>S and F>D

After much discussion on the comp.lang.forth newsgroup, a consensus was reached that F>D and F>S must truncate to zero. This is also the behaviour required by the Forth Scientific Library (FSL). Historically, MPE floating point packs permit the integer rounding mode to be set by the user. In order to support both camps, VFX Forth now behaves as follows:

Only one FP package

Only one float pack can be installed. This is checked at compile time. To replace the floating point pack use:


remove-FP-pack
include <sourcefile>

Configuration

create FP-PACK  \ -- addr
Marks that a float pack is being or has been compiled.

The value FPSYSTEM defines which floating point pack is installed and active. See the Floating Point chapters for further details. Each floating point pack defines its own type as follows:

When FPSystem changes, the following files that use FPSystem are affected:

  Extern*.fth  kernel64.fth  Tokeniser.fth
  Lib/x64/Ndpx64.fth  Lib/x64/FPSSE64.fth

At present, only 0, 2 and 4 are valid values of FPSystem in 64 systems.

#10 constant FPCELL     \ -- n
Defines the data size of floating point numbers in memory. Only 80 bit format (10 bytes) is supported. In memory and on the FP stack, this is usually aligned in a 16 byte slot.

#16 constant /NDPSLOT   \ -- n
Size of aligned memory used to hold an FP number.

/NDPSLOT negate constant -/NDPSLOT
Negative of /NDPSLOT

#18 constant #fdigits   \ -- u
Returns the largest number of usable digits available from REPRESENT. Equivalent to then environment variable MAX-FLOAT-DIGITS.

1 constant FPext?       \ -- flag
Set non-zero (default) to compile FP extensions. These extensions are particularly useful on MacOS which uses floating point numbers for screen coordinates.

false constant [fpdebug] immediate
Set this CONSTANT true when compiling Hfpx64.fth, and a debug build will be constructed. In this state, the state of the FPU is checked after each word. If a floating point exception has been generated, a diagnostic is issued, and the system aborts. Set this only when testing.

Assembler macros

These macros ease writing some FP words. Note that the FP stack is updated in 16 byte units.

: fword         \ --
Assembler FP default size, replace with TBYTE.

: >FPU       \ --
Push FNOS on FP stack to FPU.

: FPU>        \ --
Pop FTOS on FPU to FP stack

: fnext,        \ -- ; can be changed for debugging
Exit from FP word. If FPDEBUG is set, a debug version

FP constants

code f%0        \ F: -- f#(0)
Floating point 0.0

code f%1        \ F: -- f#(1)
Floating point 1.0

code f%pi       \ F: -- f#(pi)
Floating point PI

code f%pi/2     \ F: -- f#(pi/2)
Floating point PI/2

code f%pi/4     \ F: -- f#(pi/4)
Floating point PI/4

code f%lg2e     \ F: -- log2(e)
Returns log (base 2) of e.

FP control operations

: finit         \ F: i*f -- ; resets FPU and FP stack
Reset the floating point unit and the floating point stack.

code cw@        \ -- cw ; get NDP control word
Return the floating point unit Control Word.

code cw!        \ cw -- ; set NDP control word
Set the floating point unit Control Word.

code sw@        \ -- sw ; get NDP status word
Return the floating point unit Status Word.

code fclex      \ -- ; clear exceptions
Clear any pending floating point exceptions.

FP Stack operations

code fdup       \ F: f -- f f
Floating point equivalent of DUP.

code fswap      \ F: f1 f2 -- f2 f1
Floating point equivalent of SWAP.

code fdrop      \ F: f --
Floating point equivalent of DROP.

code fover      \ F: f1 f2 -- f1 f2 f1
Floating point equivalent of OVER.

code frot       \ F: f1 f2 f3 -- f2 f3 f1
Floating point equivalent of ROT.

code fpick      \ n -- ; F: -- f
Floating point equivalent of PICK. Note that because the pick index is an integer, it is on the normal Forth integer data stack, and the result, being a floating point number, is on the floating point stack.

code ndepth     \ -- n ; depth of NDP stack
Returns on the Forth data stack the number of items on the FPUs's internal working stack.

: fdepth        \ -- #f
Floating point equivalent of DEPTH. The result is reurned on the Forth data stack, NOT the float stack.

Memory operations SF@ SF! DF@ DF! etc

code f@         \ addr -- ; F: -- f
Places the contents of addr on the float stack. The size of the item fetched was 10 bytes.

code sf@        \ addr -- ; F: -- f
Places the 32 bit float at addr on the float stack.

code df@        \ addr -- ; F: -- f
Places the 64 bit double float at addr on the float stack.

code tf@        \ addr -- ; F: -- f
Places the 80 bit extended float at addr on the float stack.

code f!         \ addr -- ; F: f --
Stores the top of the float stack as an FPCELL sized number at addr.

code sf!        \ addr -- ; F: f --
Stores the top of the float stack as an 32 bit float number at addr.

code df!        \ addr -- ; F: f --
Stores the top of the float stack as an 64 bit double float number at addr.

code tf!        \ addr -- ; F: f --
Stores the top of the float stack as an 80 bit extended float number at addr.

code f+!        \ F: f -- ; addr -- ; add f to data at addr
Add F to the data at ADDR.

code f-!        \ F: f -- ; addr -- ; sub f from data at addr
Subtract F from the data at ADDR.

Dictionary operations

: tf,           \ F: f --
Lays an 80 bit extended float into the dictionary, reserving 16 bytes

: df,           \ F: f --
Lays an 64 bit double float into the dictionary, reserving 8 bytes

: sf,           \ F: f --
Lays a 32 bit float into the dictionary, reserving 4 bytes

: f,            \ F: f --
lays a default float into the dictionary, reserving /NDPSLOT bytes

: falign        \ --
Aligns the dictionary to accept a default float.

: faligned      \ addr -- addr'
Aligns the address to accept a default float.

: float+        \ addr -- addr'
Increments addr by /NDPSLOT, the size of a default float in memory.

: floats        \ n1 -- n2
Returns n2, the size of n1 default floats.

: sfalign       \ --
Aligns the dictionary to accept a 32 bit float.

: sfaligned     \ addr -- addr'
Aligns the address to accept a 32 bit float.

: sfloat+       \ addr -- addr'
Increments addr by the size of a 32 bit float.

: sfloats       \ n1 -- n2
Returns n2, the size of n1 32 bit floats.

: dfalign       \ --
Aligns the dictionary to accept a 64 bit double float.

: dfaligned     \ addr -- addr'
Aligns the address to accept a 64 bit float.

: dfloat+       \ addr -- addr'
Increments addr by the size of a 64 bit double float.

: dfloats       \ n1 -- n2
Returns n2, the size of n1 64 bit double floats.

: tfalign       \ --
Aligns the dictionary to accept an 80 bit extended float.

: tfaligned     \ addr -- addr'
Aligns the address to accept an 80 bit extended float.

: tfloat+       \ addr -- addr'
Increments addr by the size of an 80 bit extended float.

: tfloats       \ n1 -- n2
Returns n2, the size of n1 80 bit extended floats.

FP defining words

: fvariable     \ F: -- ; -- addr
Use in the form: FVARIABLE <name> to create a variable that will hold a default floating point number.

: farray                \ n -- ; i -- addr
Use in the form: n FARRAY <name> to create a variable that will hold a default floating point number. When the array name is executed, the index i is used to retun the address of the i'th 0 zero-based element in the array. For example, 5 FARRAY TEST will set up 5 array elements each containing 0, and then f n TEST F! will store f in the nth element, and n TEST F@ will fetch it.

: fconstant     \ F: f -- ; F: -- f
Use in the form: <float> FCONSTANT <name> to create a constant that will return a floating point number.

: fvalue        \ F: f -- ; ??? -- ???
Use in the form: <float> FVALUE <name> to create a floating point version of VALUE that will return a floating point number by default, and that can accept the operators TO, ADDR, ADD, SUB, and SIZEOF.

Basic functions + - * / and others

code f+         \ f1 f2 -- f1+f2
Floating point add.

code f-         \ f1 f2 -- f1-f2
Floating point subtract.

code f*         \ f1 f2 -- f1*f2
Floating point multiply.

code f/         \ f1 f2 -- f1/f2
Floating point divide.

code fmod       \ F: f1 f2 -- f3
Floating point modulus. Returns f3 the remainder after repeatedly subtracting f2 from f1. Often used to force arguments to lie in the range: 0 <= arg < f2

code fsqrt      \ F: f -- sqrt(f)
Floating point square root.

code 1/f        \ F: f -- 1/f
Floating point reciprocal.

code fabs       \ F: f -- |f|
Floating point absolute.

code fnegate    \ F: f -- -f
Floating point negate.

code f2*        \ F: f -- f*2
Floating point multiply by two.

code f2/        \ F: f -- f/2
Floating point divide by two.

Integer to FP conversion

code CLZ        \ x -- u
Return the number of leading zeros in x.

: DCLZ          \ dx -- u
Return the number of leading zeros in the double dx.

: D>F           \ d -- ; F: -- fn
Converts a double integer to a float.

: f>d           \ F: f -- ; -- dint(f)
Converts an 80 bit float to a double integer. Note that F>D truncates the number towards zero according to the ANS specification.

: s>f           \ n -- ; F: -- f
Converts a single integer to a float.

: f>s           \ F: f -- ; -- n ; convert float to integer
Converts a float to a single integer. Note that F>S truncates the number towards zero according to the ANS specification.

code fr>s       \ F: f -- ; -- n ; convert float to integer
Converts a float to a single integer using the current rounding mode.

: fr>d  \ F: f -- ; -- d ; convert float to double integer
Converts a float to a double integer using the current rounding mode.

FP comparisons

: f0<           \ F: f1 -- ; -- t/f ; less than zero?
Floating point 0<. N.B. result is on the Forth integer data stack.

: f0=           \ F: f1 -- ; -- t/f ; equal zero?
Floating point 0=. N.B. result is on the Forth integer data stack.

: f0<>          \ F: f1 -- ; -- t/f ; not equal zero?
Floating point 0<>. N.B. result is on the Forth integer data stack.

: f0>           \ F: f1 -- ; -- t/f ; greater than zero?
Floating point 0>. N.B. result is on the Forth integer data stack.

: f<            \ F: f1 f2 -- ; -- t/f ; one less than the other?
Floating point <. N.B. result is on the Forth integer data stack.

: f=            \ F: f1 f2 -- ; -- t/f ; equal each other?
Floating point =. N.B. result is on the Forth integer data stack.

: f<>           \ F: f1 f2 -- ; -- t/f ; one not equal the other?
Floating point <>. N.B. result is on the Forth integer data stack.

: f>            \ F: f1 f2 -- ; -- t/f ; one less than the other?
Floating point >. N.B. result is on the Forth integer data stack.

: f<=           \ F: f1 f2 -- ; -- t/f ; one less or equal the other?
Floating point <=. N.B. result is on the Forth integer data stack.

: f>=           \ F: f1 f2 -- ; -- t/f ; one greater or equal the other?
Floating point >=. N.B. result is on the Forth integer data stack.

: f~            \ F: f1 f2 f3 -- ; -- flag
Approximation function. If f3 is positive, flag is true if abs[f1-f2] is less than f3. If f3 is zero, flag is true if the f2 is exactly equal to f1. If f3 is negative, flag is true if abs[f1-f2] less than abs[f3*abs[f1+f2]].

Words dependent on FP compares

: ?fnegate      \ F: f1 f2 -- f3
Floating point NEGATE.

: fmax          \ F: f1 f2 -- f3
Floating point MAX.

: fmin          \ F: f1 f2 -- f3
Floating point MIN.

FP logs and powers

code flog       \ F: f -- log(f)
Floating point log base 10.

code fln        \ F: f -- ln(f)
Floating point log base e.

code 2**        \ F: f -- 2^f
Floating point: returns 2^F.

code fexp       \ F: f -- e^f ; was called FE^X
Floating point e^f.

: fexpm1        \ F: f -- (e^f)-1 ; 12.6.2.1516
Floating point log base (e^f)-1.

code falog      \ F: f -- 10^f ; was called f10^f, new name: ans
Floating point anti-log base 10.

code (f**)      \ F: f1 f2 -- f1^f2
Floating point returns f1 raised to the power f2. N.B. no error checking is performed. If floating point execeptions are masked, which is the default condition, the system will return a NaN for f1<0.

: f**           \ F: f1 f2 -- f1^f2 ; was called fx^y ; SFP009
Floating point: returns f1 raised to the power f2. If f1<=0e0, 0e0 is returned. This behaviour is required by the Forth Scientific Library.

Rounding

The default rounding configuration is round to nearest.

: fround        \ F: f1 -- f1'
Round the number to nearest or even.

: fint          \ F: f1 -- f1'
Chop the number towards zero.

: floor         \ F: f1 -- f1'
Floored round towards -infinity.

: roundup       \ F: f1 -- f1'
Round towards +infinity.

: rounded       \ -- ; set NDP to round to nearest
Set NDP to round to nearest for all operations other than FINT FLOOR and ROUNDUP.

: floored       \ -- ; set NDP to floor
Set NDP to round to floor for all operations other than FROUND FINT and ROUNDUP.

: roundedup     \ -- ; set NDP to round up
Set NDP to round up for all operations other than FROUND FINT and FLOOR.

: truncated     \ -- ; set NDP to chop to 0
Set NDP to chop to 0 for all operations other than FROUND FLOOR and ROUNDUP.

defer fliteral  \ F: f -- ; F: -- f
Compiles a float as a literal into the current definition. At execution time, a float is returned. For example, [ F%PI F2* ] FLITERAL will compile 2PI as a floating point literal. Note that FLITERAL is immediate, whereas (RLITERAL) below is not.

: (rliteral)    \ F: f -- ; F: -- f
Compiles a float as a literal into the current definition. At execution time, a float is returned. For example, [ F%PI F2* ] FLITERAL will compile 2PI as a floating point literal. The default action of FLITERAL. Note that FLITERAL is immediate, whereas [FLITERAL] is not.

FP trigonometry

code ftan       \ F: f -- tan(f)
Floating point tangent.

code fatan      \ F: f -- atan(f)
Floating point arctangent.

code fsin       \ F: f -- sin(f)
Floating point sine.

code fasin      \ F: f -- asin(f)
Floating point arcsine.

code fcos       \ F: f -- cos(f)
Floating point cosine.

code facos      \ F: f -- acos(f)
Floating point arctangent.

code fsincos    \ F: f -- sin(f) cos(f)
Returns sine and cosine values of f.

code fatan2     \ F: f1 f2 -- atan(f1/f2)
Floating point arctangent with prior division.

: deg>rad       \ F: fdeg -- frad
Converts a value in degrees to radians.

: rad>deg               \ -- ;
Converts a value in radians to degrees.

code freduce    \ F: f1 -- f2 ; reduce value to range 0..2pi
Reduce f1 to be in the range 0 <= f2 < 2PI.

: fcosec        \ F: f -- cosec(f)
Floating point cosecant.

: fsec          \ F: f -- sec(f)
Floating point secant.

: fcotan        \ f: f -- cot(f)
Floating point cotangent.

: fsinh         \ F: f -- sinh(f) ; (e^x - 1/e^x)/2
Floating point hyberbolic sine.

: fcosh         \ F: f -- cosh(f) ; (e^x + 1/e^x)/2
Floating point hyberbolic cosine.

: ftanh         \ F: f -- tanh(f) ; (e^x - 1/e^x)/(e^x + 1/e^x)
Floating point hyberbolic tangent.

: fasinh        \ F: f -- asinh(f) ; ln(f+sqrt(1+f*f))
Floating point hyberbolic arcsine.

: facosh        \ F: f -- acosh(f) ; ln(f+sqrt(f*f-1))
Floating point hyberbolic arccosine.

: fatanh        \ F: f -- atanh(f) ; ln((1+f)/(1-f))/2
Floating point hyberbolic arctangent.

Number conversion

: 10**n         \ n -- ; -- f
Generate a floating point value 10 to the power n, where n is an integer.

: >FLOAT        \ c-addr u -- flag ; F: -- f | --
Try to convert the string at c-addr/u to a floating point number. If conversion is successful, flag is returned true, and a floating number is returned on the float stack, otherwise flag is returned false and the float stack is unchanged.

FP output

A significant portion of the output code is taken from FPOUT v3.7 by Ed.

: precision     \ -- u
Returns the number of significant digits used by F. FE. and FS..

: set-precision \ u --
Sets the number of significant digits used by F. FE. and FS..

: places        \ u --
Sets the number of significant digits used by F. FE. and FS.. The ANS version of this word is SET-PRECISION, which should be used in new code.

: BadFloat?     \ F: f -- ; -- caddr u true | false
If the float is a NaN or Infinite, return a string such as "+NaN" and true, otherwise just return false (0).

: represent     \ c-addr u -- n flag1 flag2 ; F: f --
Assume that the floating number is of the form +/-0.xxxxEyy. Round the significand xxxxx to u significant digits and place its representation at c-addr. If u is zero round the fractional significand to a whole number. flag2 is true if the results are valid. n is the signed integer version of yy and flag1 is true if f is negative. In this implementation all errors are handled by exceptions, and so flag2 is always true, except for NaNs and Infinites. The number of characters at c-addr is the greater of u or MAX-FLOAT-DIGITS.

: (FS.)         \ F: f -- ; n -- c-addr u
Convert float f to a string c-addr/u in scientific notation with n places right of the decimal point.

: FS.R          \ F: r -- ; n u --
Display float f in scientific notation right-justified in a field width u with n places right of the decimal point.

: FS.           \ F: f --
Display float f in scientific notation, with one digit before the decimal point and a trailing space.

: (FE.)         \ F: r -- ; n -- c-addr u
Convert float f to a string c-addr u in engineering notation with n places right of the decimal point.

: FE.R          \ F: r -- ; n u --
Display float f in engineering notation right-justified in a field width u with n places right of the decimal point.

: FE.           \ F: f --
Display float f in engineering notation, in which the exponent is always a power of three, and the significand is always in the range 1.xxx to 999.xxx.

: (F.)          \ F: f -- ; n -- c-addr u
Convert float f to string c-addr/u in fixed-point notation with n places right of the decimal point.

: F.R           \ F: f -- ; n u --
Display float f in fixed-point notation right-justified in a field width u with n places right of the decimal point.

: F.            \ F: f --
Display f as a float in fixed point notation with a trailing space. Convert float f to string c-addr/u with n places right of the decimal point. Fixed-point is used if the exponent is in the range -4 to 5 otherwise scientific notation is used.

: G.R           \ F: f -- ; n u --
Display float f right-justified in a field width u with n places right of the decimal point. Fixed-point is used if the exponent is in the range -4 to 5 otherwise scientific notation is used.

: G.            \ F: f --
Display float f followed by a space. Floating-point is used if the exponent is in the range -4 to 5 otherwise use scientific notation. Non-essential zeros and signs are removed.

: f?            \ addr -- ; displays contents of FVARIABLE
Displays the contents of the given FVARIABLE.

: f.s           \ F: i*f -- i*f
Display the contents of the floating point stack.

: isFnumber?    \ caddr len -- 0 | n 1 | d 2 | -2 ; F: -- r
Behaves like the integer version of isNumber? except that if integer conversion fails, and BASE is decimal, a floating point conversion is attempted. If conversion is successful, the floating point number is left on the float stack and the result code is -2.

: Fnumber?      \ caddr -- 0 | n 1 | d 2 | -2 ; F: -- r
As isFnumber? above, but takes a counted string.

: post-float    \ f: f -- ; --
POSTPONE a floating point number. The word being defined will itself compile the given floating point number.

' noop  ' (rliteral)  ' post-float  RecType: r:float    \ -- struct
Contains the interpret, compile and postpone actions for floating point literals.

: rec-float     \ caddr u -- r:float | r:fail ; F: -- [f]
The parser part of the floating point recogniser.

: .FSysPrompt   \ --
Adds floating point stack depth display.

: reals         \ -- ; turn FP system on
Enables the floating point package for number conversion.

: integers      \ -- ; turn FP system off
Disables the floating point package for number conversion.

PFW2.x compatibility

: f#            \ -- f ; or compiles it [ state smart ]
Used in the form "F# <number>", the <number> string is converted and promoted if required to a floating point number. If the system is compiling the float is compiled. If <number> cannot be an error occurs.

Debugging support

Debugging floating point code is often difficult, as failures can occur because of the necessary approximations involved in floating point operations.

If you set the constant [FPDEBUG] true when compiling HFP387.FTH, a debug build will be constructed. The state of the FPU will be checked after each word. If a floating point exception has been generated, a diagnostic is issued, and the system aborts. Set this only when testing, as it slows down the normal operation of floating point words.

The debugger works by intercepting the end of each code definition which is finished by FNEXT, rather than the normal NEXT, or RET. See the source code in LIB\x86\HFP387.FTH for more details.

: +fpcheck       \ -- ; enable FP checking
Enables the floating point debugger if it has been compiled.

: -fpcheck       \ -- ; disable FP checking
Disbles the floating point debugger if it has been compiled.

Extensions

F.P. stack jugglers

Due to the Mac's usage of fp for all graphic related things, F.P. stack jugglers similar to those for the data stack are handy. We deal with F.P. pairs as used for points, sizes and ranges and F.P. quads for rectangles and colours. F2SWAP F2OVER F2DROP F4DUP FTUCK FNIP do what you expect ...

code F2DUP      \ F: r1 r2 -- r1 r2 r1 r2
Floating point equivalent of 2DUP.

code F2DUP      \ F: r1 r2 -- r1 r2 r1 r2
Floating point equivalent of 2DUP.

code F2SWAP     \ F: r1 r2 r3 r4 -- r3 r4 r1 r2
Floating point equivalent of 2SWAP.

code F2OVER     \ F: r1 r2 r3 r4 -- r1 r2 r3 r4 r1 r2
Floating point equivalent of 2OVER.

code F2DROP     \ F: r1 r2 --
Floating point equivalent of 2OVER.

code F4DUP      \ F: r1 r2 r3 r4 -- r1 r2 r3 r4 r1 r2 r3 r4
Floating point equivalent of 4DUP.

code FTUCK      \ F: r1 r2 -- r2 r1 r2
Floating point equivalent of TUCK.

Installation code

: HFP64setup    \ --
Set up the Forth system for 80 bit NDP floats. Performed at start up.