I coded these few FORTH words to probe into the QL floating point format, and found interesting things...
Code: Select all
.( Probing into QL floating point format ) cr
: .. ( n<256 --- ) 0 <# # # #> TYPE ." " ;
: ... ( n --- ) 256 /MOD .. .. ;
: .W ( 16bit --- ) BASE @ >R HEX ... R> BASE ! ;
: .L ( 32bit --- ) BASE @ >R HEX ... ... R> BASE ! ;
: .F ( float --- ) BASE @ >R HEX ... ... ... R> BASE ! ;
: .Q FDUP .F ." " F. ;
: *2 0 DO FDUP .Q CR F# 2 F* LOOP .Q CR ;
: /2 0 DO FDUP .Q CR F# 2 F/ LOOP .Q CR ;
Do not use the ancillary words .. and ...
The .W word expects a 16bit number (2 bytes) on the stack and displays it like 2 hex bytes. You use it like this (your input bold ! to signal to FORTH a 16bit integer, type simply the digits) :
1 .W
00 01 ok
The .L word expects a 32bit number (4 bytes) on the stack and displays it like 4 hex bytes. You use it like this (to signal to FORTH a 32bit integer, put a dot somewhere within the digits) :
1. .L
00 00 00 01 ok
The .F word expects a float number (6 bytes - QL float format) on the stack and displays it like 6 hex bytes. To input a float, just type F# in front of what you would input with SuperBasic :
F# 1.0 .F
08 01 40 00 00 00 ok
The .Q word expects also a float number on the stack but displays it both like 6 hex bytes and as a float (in the same format as with SuperBasic PRINT)
The two following words *2 and /2 expect you to input first a float and then an integer before executing them and will output a table of ".Q results" :
Code: Select all
F# 1.0 32 *2
08 01 40 00 00 00 1
08 02 40 00 00 00 2
08 03 40 00 00 00 4
08 04 40 00 00 00 8
08 05 40 00 00 00 16
08 06 40 00 00 00 32
08 07 40 00 00 00 64
08 08 40 00 00 00 128
08 09 40 00 00 00 256
08 0A 40 00 00 00 512
08 0B 40 00 00 00 1024
08 0C 40 00 00 00 2048
08 0D 40 00 00 00 4096
08 0E 40 00 00 00 8192
08 0F 40 00 00 00 16384
08 10 40 00 00 00 32768
08 11 40 00 00 00 65536
08 12 40 00 00 00 131072
08 13 40 00 00 00 262144
08 14 40 00 00 00 524288
08 15 40 00 00 00 1.048576E6
08 16 40 00 00 00 2.097152E6
08 17 40 00 00 00 4.194304E6
08 18 40 00 00 00 8.388608E6
08 19 40 00 00 00 1.677722E7
08 1A 40 00 00 00 3.355443E7
08 1B 40 00 00 00 6.710886E7
08 1C 40 00 00 00 1.342177E8
08 1D 40 00 00 00 2.684355E8
08 1E 40 00 00 00 5.368709E8
08 1F 40 00 00 00 1.073742E9
08 20 40 00 00 00 2.147484E9
08 21 40 00 00 00 4.294967E9
ok
F# 1.0 32 /2
08 01 40 00 00 00 1
08 00 40 00 00 00 .5
07 FF 40 00 00 00 .25
07 FE 40 00 00 00 .125
07 FD 40 00 00 00 6.25E-2
07 FC 40 00 00 00 3.125E-2
07 FB 40 00 00 00 1.5625E-2
07 FA 40 00 00 00 7.8125E-3
07 F9 40 00 00 00 3.90625E-3
07 F8 40 00 00 00 1.953125E-3
07 F7 40 00 00 00 9.765625E-4
07 F6 40 00 00 00 4.882813E-4
07 F5 40 00 00 00 2.441406E-4
07 F4 40 00 00 00 1.220703E-4
07 F3 40 00 00 00 6.103516E-5
07 F2 40 00 00 00 3.051758E-5
07 F1 40 00 00 00 1.525879E-5
07 F0 40 00 00 00 7.629395E-6
07 EF 40 00 00 00 3.814697E-6
07 EE 40 00 00 00 1.907349E-6
07 ED 40 00 00 00 9.536743E-7
07 EC 40 00 00 00 4.768372E-7
07 EB 40 00 00 00 2.384186E-7
07 EA 40 00 00 00 1.192093E-7
07 E9 40 00 00 00 5.960464E-8
07 E8 40 00 00 00 2.980232E-8
07 E7 40 00 00 00 1.490116E-8
07 E6 40 00 00 00 7.450581E-9
07 E5 40 00 00 00 3.72529E-9
07 E4 40 00 00 00 1.862645E-9
07 E3 40 00 00 00 9.313226E-10
07 E2 40 00 00 00 4.656613E-10
07 E1 40 00 00 00 2.328306E-10
ok
I wrote also two SuperBasic procedures to compare its printing of floats with the output of the FORTH Q. word (part of the floating point extensions like F# ).
Code: Select all
REM SuperBasic procedure doing the same thing than *2
100 DEFine PROCedure QLFM(FLA,K)
110 OPEN #5,flp2_bobo
120 FOR i = 1 TO K
130 PRINT#5,FLA
140 FLA=FLA*2
150 END FOR i
160 PRINT#5,FLA
170 CLOSE#5
180 END DEFine QLFM
Code: Select all
REM SuperBasic procedure doing the same thing than /2
100 DEFine PROCedure QLFD(FLA,K)
110 OPEN #5,flp2_bobo
120 FOR i = 1 TO K
130 PRINT#5,FLA
140 FLA=FLA/2
150 END FOR i
160 PRINT#5,FLA
170 CLOSE#5
180 END DEFine QLFD
The output is absolutely the same !
This means that the FORTH floating point extensions simply send what you typed after F# like a string to SuperBasic floating point conversion routine and get back 6 bytes following QL float format. And that the F. word simply sends 6 bytes to SuperBasic floating point print formatting routine and gets back a string to display (exactly the same as SuperBasic would print). And all the other floating point extensions words simply call Qdos floating point engine routines. No hassle, no fuss !... for the ComputerOne FORTH designers
What playing with the .Q and the *2 and /2 is learning us about QL floating point internal format :
The first two bytes code the exponent, but only on their 12 L.S.bits
0800 means *2**0
0801 means *2**1
0802 means *2**2
etc.
07FF means /2**1
07FE means /2**2
etc.
The four following bytes are the mantissa with values going from (with exponent 0800) :
40000000 meaning +0.5
to
7FFFFFFF meaning +1.0 (almost)
and from
80000000 meaning -1.0
to
BFFFFFFF meaning -0.5 (almost)
mantissa Values under 40000000 or over BFFFFFFF are valid for the floating point engine, but are not generated by it.
Zero has this special format : 0000 (exp.) 00000000 (mant.)
Bye Paul