ZX Basic Features
The ‘Division Error’
If you run the following program on a standard Spectrum, or on an emulator with the standard ROM, then the results are predictably correct.
10 PRINT .25 = 1/4
20 PRINT .9999999948
30 FOR I = 0 TO 1 STEP .25 : PRINT I : NEXT I : PRINT “end”
If you run the same program on an emulator using a modified ROM, with the corrected “division error”, then the results are somewhat inaccurate.
Normal ZX ROM Modified ROM
1 0
.99999999 1
0 0
0.25 0.25
0.5 0.5
0.75 0.75
1.0 end
end
Clearly something is amiss.
Floating-point Arithmetic
The ZX81 and the ZX Spectrum use a similar floating-point number representation and the following applies to both machines.
A four byte, 32-bit mantissa is used with the most significant bit, the implied set bit, being used as a sign bit for the number.
This bit is reset to denote a positive number and left set to denote a negative number.
The byte that precedes the mantissa is the exponent byte. This holds the number of times the imaginary decimal point that precedes the mantissa has to be moved to restore the number from it’s normalized state.
The normal state is when the bits of the mantissa are moved left (or right) so that the most significant bit is set.
A number like a half ( .1 binary ) or three-quarters ( .11 binary) is already normalized and has a plus zero exponent ( $80).
A number like a quarter ( .01 binary ) is shifted left and the exponent decreased ( $7F ).
A vast range of numbers, of which 1/65536 through 65536 is just a small subset, can be held accurately with a mantissa consisting of four zero bytes.
In contrast, just as a third cannot be held accurately in the decimal system (giving .33333 recurring), so a tenth cannot be held accurately in a binary mantissa and becomes .00110011 recurring. Only machines like the Jupiter Ace, which use Binary Coded Decimal, can hold a tenth accurately.
Table 1.
|
ROMS |
ZX ROM |
Div 34th |
DEC-TO-FP |
BOTH |
Internal Storage |
||||
|
.5 |
7F 7F FF FF FF |
80 00 00 00 00 |
80 00 00 00 00 |
80 00 00 00 00 |
|
½ |
80 00 00 00 00 |
80 00 00 00 00 |
80 00 00 00 00 |
80 00 00 00 00 |
|
.25 |
7E 7F FF FF FF |
7F 00 00 00 01 |
7E 7F FF FF FF |
7F 00 00 00 00 |
|
¼ |
7F 00 00 00 00 |
7F 00 00 00 00 |
7F 00 00 00 00 |
7F 00 00 00 00 |
|
.125 |
7D 7F FF FF FF |
7E 00 00 00 01 |
7D 7F FF FF FF |
7E 00 00 00 00 |
|
1/8 |
7E 00 00 00 00 |
7E 00 00 00 00 |
7E 00 00 00 00 |
7E 00 00 00 00 |
|
.0625 |
7C 7F FF FF FF |
7D 00 00 00 01 |
7C 7F FF FF FF |
7D 00 00 00 00 |
|
1/16 |
7D 00 00 00 00 |
7D 00 00 00 00 |
7D 00 00 00 00 |
7D 00 00 00 00 |
|
.03125 |
7C 00 00 00 00 |
7C 00 00 00 01 |
7C 00 00 00 00 |
7C 00 00 00 01 |
|
1/32 |
7C 00 00 00 00 |
7C 00 00 00 00 |
7C 00 00 00 00 |
7C 00 00 00 00 |
|
.015625 |
7B 00 00 00 00 |
7B 00 00 00 01 |
7B 00 00 00 00 |
7B 00 00 00 00 |
|
1/64 |
7B 00 00 00 00 |
7B 00 00 00 00 |
7B 00 00 00 00 |
7B 00 00 00 00 |
|
.0078125 |
79 7F FF FF FF |
7A 00 00 00 01 |
7A 00 00 00 00 |
7A 00 00 00 00 |
|
1/128 |
7A 00 00 00 00 |
7A 00 00 00 00 |
7A 00 00 00 00 |
7A 00 00 00 00 |
|
.00390625 |
79 00 00 00 00 |
79 00 00 00 01 |
79 00 00 00 00 |
79 00 00 00 00 |
|
1/256 |
79 00 00 00 00 |
79 00 00 00 00 |
79 00 00 00 00 |
79 00 00 00 00 |
|
.001953125 |
77 7F FF FF FF |
78 00 00 00 01 |
77 7F FF FF FF |
78 00 00 00 00 |
|
1/512 |
78 00 00 00 00 |
78 00 00 00 00 |
78 00 00 00 00 |
78 00 00 00 00 |
|
.000976525 |
76 7F FF FF FF |
77 00 00 00 01 |
76 7F FF FF FF |
77 00 00 00 00 |
|
1/1024 |
77 00 00 00 00 |
77 00 00 00 00 |
77 00 00 00 00 |
77 00 00 00 00 |
Boolean Logic |
||||
|
.5 = 1/2 |
TRUE |
TRUE |
TRUE |
TRUE |
|
½ = .5 |
FALSE |
TRUE |
TRUE |
TRUE |
|
.25 = 1/4 |
TRUE |
FALSE |
TRUE |
TRUE |
|
¼ = .25 |
FALSE |
FALSE |
FALSE |
TRUE |
|
.125 = 1/8 |
TRUE |
FALSE |
TRUE |
TRUE |
|
1/8 =.125 |
FALSE |
FALSE |
FALSE |
TRUE |
|
.0625 = 1/16 |
TRUE |
FALSE |
TRUE |
TRUE |
|
1/16 = .0625 |
FALSE |
FALSE |
FALSE |
TRUE |
|
.03125 = 1/32 |
TRUE |
FALSE |
TRUE |
FALSE |
|
1/32 = .03125 |
TRUE |
FALSE |
TRUE |
FALSE |
|
.015625 = 1/64 |
TRUE |
FALSE |
TRUE |
TRUE |
|
1/64 = .015625 |
TRUE |
FALSE |
TRUE |
TRUE |
|
.0078125 = 1/128 |
TRUE |
FALSE |
TRUE |
TRUE |
|
1/128 = .0078125 |
FALSE |
FALSE |
TRUE |
TRUE |
|
.00390625=1/256 |
TRUE |
FALSE |
TRUE |
TRUE |
|
1/256=.00390625 |
TRUE |
FALSE |
TRUE |
TRUE |
Fractional Loop Steps |
||||
|
.5 |
CORRECT |
CORRECT |
CORRECT |
CORRECT |
|
.25 |
CORRECT |
WRONG |
CORRECT |
CORRECT |
|
.125 |
CORRECT |
WRONG |
CORRECT |
CORRECT |
|
.0625 |
CORRECT |
WRONG |
CORRECT |
CORRECT |
|
.03125 |
CORRECT |
WRONG |
CORRECT |
WRONG |
|
.015625 |
CORRECT |
WRONG |
CORRECT |
CORRECT |
|
.0078125 |
CORRECT |
WRONG |
CORRECT |
CORRECT |
Print values |
||||
|
.123456785 |
0.12345678 |
0.12345679 |
0.12345678 |
0.12345678 |
|
.100000015 |
0.10000001 |
0.10000002 |
0.10000001 |
0.10000002 |
|
.200000015 |
0.20000002 |
0.20000002 |
0.20000002 |
0.20000002 |
|
.876543215 |
||||