Doubles
By default, numbers entered into Forth are assumed to be 16-bit (either -32768 to 32767 signed, or 0 to 65535 unsigned), and the results of arithmetic operations are also 16-bit.
Forth is capable of working with 32-bit (double) numbers, 48-bit number (triples) and 64-bit numbers (quads). Sorry folks, this is where it gets a little weird. A 32-bit number is created by placing a dot at the end of the number, without a space. Let’s look at doing this in hex first, as it’s easier to follow. In this example, we put Forth into base 16 (hex) first, then we enter the 32-bit number suffixed with a dot, then look at the stack:
Forth is capable of working with 32-bit (double) numbers, 48-bit number (triples) and 64-bit numbers (quads). Sorry folks, this is where it gets a little weird. A 32-bit number is created by placing a dot at the end of the number, without a space. Let’s look at doing this in hex first, as it’s easier to follow. In this example, we put Forth into base 16 (hex) first, then we enter the 32-bit number suffixed with a dot, then look at the stack:
hex
12345678.
.s
.s gives the output 5678 1234. The 32-bit number is stored as two 16-bit numbers on the stack, with the most-significant 16 bits as the top of stack. It looks backwards to us, but to FlashForth it makes sense. It will work with the 32-bit number correctly.
Now for a 32-bit number in decimal:
Now for a 32-bit number in decimal:
decimal
67898.
.s
.s gives the output 2362 1.
It’s not an error. That’s decimal 67898 split across two 16-bit words. The 1 at the top of the stack represents 65636 (a full 16-bit number… $ffff + 1). 65636 + 2362 = 67898. Rest assured the number is stored correctly, it just appears a little odd when you (a human) looks at the stack in decimal. Keep this in mind when working with doubles, triples and quads.
To view a 32-bit (double) number in a more readable way, use the d. (“d dot”) word to print it out as a double:
It’s not an error. That’s decimal 67898 split across two 16-bit words. The 1 at the top of the stack represents 65636 (a full 16-bit number… $ffff + 1). 65636 + 2362 = 67898. Rest assured the number is stored correctly, it just appears a little odd when you (a human) looks at the stack in decimal. Keep this in mind when working with doubles, triples and quads.
To view a 32-bit (double) number in a more readable way, use the d. (“d dot”) word to print it out as a double:
67898.
d.
There are a number of words that perform double arithmetic:
d+ adds two double numbers, while d- subtracts one double number from the other.
d2* multiplies by the double number by 2, while d2/ divides by 2.
m+ adds single number (16-bit) to a double (32-bit) number.
m* multiples two signed 16-bit numbers to give a 32-bit result.
um* does an unsigned multiply on two 16-bit numbers to give a 32-bit result.
ud* multiplies an unsigned 32-bit number with a 16-bit number giving a 32-bit result.
um/mod divides an unsigned double by an unsigned single, leaving the 16-bit remainder and 16-bit quotient on the stack.
ud/mod is an unsigned 32-bit/16-bit division, leaving a 16-bit remainder and 32-bit quotient on the stack.
sm/rem divides a signed double by a signed single, leaving the 16-bit remainder and 16-bit quotient on the stack.
um*/ performs an unsigned multiplication of a double by single, then division by a single (ud1, u1, u2). The operator multiples ud1 by u1, then divides by u2.
dabs converts a double to its absolute value.
dnegate negates a double number.
A 32-bit constant can be created using the word 2constant. First a double is placed on the stack, then the double constant is created:
d+ adds two double numbers, while d- subtracts one double number from the other.
d2* multiplies by the double number by 2, while d2/ divides by 2.
m+ adds single number (16-bit) to a double (32-bit) number.
m* multiples two signed 16-bit numbers to give a 32-bit result.
um* does an unsigned multiply on two 16-bit numbers to give a 32-bit result.
ud* multiplies an unsigned 32-bit number with a 16-bit number giving a 32-bit result.
um/mod divides an unsigned double by an unsigned single, leaving the 16-bit remainder and 16-bit quotient on the stack.
ud/mod is an unsigned 32-bit/16-bit division, leaving a 16-bit remainder and 32-bit quotient on the stack.
sm/rem divides a signed double by a signed single, leaving the 16-bit remainder and 16-bit quotient on the stack.
um*/ performs an unsigned multiplication of a double by single, then division by a single (ud1, u1, u2). The operator multiples ud1 by u1, then divides by u2.
dabs converts a double to its absolute value.
dnegate negates a double number.
A 32-bit constant can be created using the word 2constant. First a double is placed on the stack, then the double constant is created:
1272772. 2constant myDConstant
A 32-bit variable can be created using the word 2variable, and accessed using 2! and 2@. First a double is placed on the stack, then the double constant is created:
2variable my32bitVar
1272772. my32bitVar 2!
Triples and Quads
There are a number of words that perform triple (48-bit) and quad (64-bit) arithmetic:
q+ adds two quad numbers.
qm+ adds a double to a quad.
uq* unsigned 32x32 multiple, giving a 64-bit result.
ut* unsigned 32x16 multiply, giving a 48-bit result.
ut/ divides a triple by a single.
uq/mod divides a quad by a double, leaving a double remainder and a double quotient on the stack.
q+ adds two quad numbers.
qm+ adds a double to a quad.
uq* unsigned 32x32 multiple, giving a 64-bit result.
ut* unsigned 32x16 multiply, giving a 48-bit result.
ut/ divides a triple by a single.
uq/mod divides a quad by a double, leaving a double remainder and a double quotient on the stack.