Floating Point Numbers
-
- RWAP Master
- Posts: 2892
- Joined: Sun Nov 28, 2010 4:51 pm
- Location: Stone, United Kingdom
- Contact:
Re: Floating Point Numbers
You have to be careful when using the RANDOMISE command...
If you are using it in a program which runs as soon as the QL boots up, it will always be seeded with the same value (as the same amount of time will have passed since the QL was switched on!)...
RANDOMISE DATE would work a bit better if the QL is equipped with a battery backed clock...
The only real way of getting a truly random number without a battery backed clock, is for the program to include a prompt for the user to press a key before the RANDOMISE command, as the user will not always take the same amount of time to press the key or answer a question...
If you are using it in a program which runs as soon as the QL boots up, it will always be seeded with the same value (as the same amount of time will have passed since the QL was switched on!)...
RANDOMISE DATE would work a bit better if the QL is equipped with a battery backed clock...
The only real way of getting a truly random number without a battery backed clock, is for the program to include a prompt for the user to press a key before the RANDOMISE command, as the user will not always take the same amount of time to press the key or answer a question...
Rich Mellor
RWAP Software
RWAP Adventures
SellMyRetro
Retro-Printer Module - add a USB printer to your QL
Also Involved in:
Icephorm
RWAP Software
RWAP Adventures
SellMyRetro
Retro-Printer Module - add a USB printer to your QL
Also Involved in:
Icephorm
Re: Floating Point Numbers
And why not a prompt asking the user to enter the actual date ? Then you would have a "user backup'ed clock" QL at the same time.The only real way of getting a truly random number without a battery backed clock, is for the program to include a prompt for the user to press a key before the RANDOMISE command

My own (paradoxical) way to use the RANDOMISE command was to give it always the same parameter value, in order to get always the same random number sequence



Paul
May the FORTH be with you !
POLKa
POLKa
Re: Floating Point Numbers
Well, RANDOMISE is probably the most mis-understood keyword in all BASICs.
Most people seem to think it has been introduced to allow you to make RND more random. But it's just the opposite - By default, RND is just about as random as it can be. Try starting a program containing RND (from the command line, not from BOOT) and cmpare the results. You'll get a different sequence of numbers every time.
for i = 1 to 10 : PRINT RND (1 TO 10)&" "
Will create a different sequence of random numbers every time.
RANDOMISE 100 : FOR i = 1 TO 10 : PRINT RND(1 TO 10)&" "
Will create the same sequence every time
RANDOMISE actually is there to make the "randomnesss" reproducable.
The easiest way to make RND really random would be
PRINT "Press any key to continue" : PAUSE -1 : RANDOMISE
This puts a bit of randomness into the seed, depending on how long the user waits to press a key (RANDOMISE uses some sort of "elapsed time since BOOT" as seed)
With RANDOMISE giving a reproducable sequence of "random" numbers for the same seed you can do interesting things, like for example cyphering a string with a known sequence and deciphering it only if the same seed is given for RANDOMISE again.
That's probably worth an article in one of the QL publications, though
Most people seem to think it has been introduced to allow you to make RND more random. But it's just the opposite - By default, RND is just about as random as it can be. Try starting a program containing RND (from the command line, not from BOOT) and cmpare the results. You'll get a different sequence of numbers every time.
for i = 1 to 10 : PRINT RND (1 TO 10)&" "
Will create a different sequence of random numbers every time.
RANDOMISE 100 : FOR i = 1 TO 10 : PRINT RND(1 TO 10)&" "
Will create the same sequence every time
RANDOMISE actually is there to make the "randomnesss" reproducable.
The easiest way to make RND really random would be
PRINT "Press any key to continue" : PAUSE -1 : RANDOMISE
This puts a bit of randomness into the seed, depending on how long the user waits to press a key (RANDOMISE uses some sort of "elapsed time since BOOT" as seed)
With RANDOMISE giving a reproducable sequence of "random" numbers for the same seed you can do interesting things, like for example cyphering a string with a known sequence and deciphering it only if the same seed is given for RANDOMISE again.
That's probably worth an article in one of the QL publications, though

ʎɐqǝ ɯoɹɟ ǝq oʇ ƃuᴉoƃ ʇou sᴉ pɹɐoqʎǝʞ ʇxǝu ʎɯ 'ɹɐǝp ɥO
- Mr_Navigator
- QL Fanatic
- Posts: 782
- Joined: Mon Dec 13, 2010 11:17 pm
- Location: UK, Essex
- Contact:
Re: Floating Point Numbers
Thanks for the replies, I was only using the RANDOMISE TIMER as an example, not that I wanted to use it. BTW on a PC using the RND function in QuickBASIC would always provide the same results each time you ran the program, the RND function wasn't that random and hence the need to use the RANDOMISE TIMER to ensure it was more random. In most computer systems the RND number generator was a fairly complex algorithm anyway so not truely random.
Memory jog - For those who remember the COMPUKIT UK 101 home built computer around the 1979, there was another similar computer system in kit form I seem to recall (but I could be wrong) that used the physical random noise generated by an open ended diode or transistor and used those signals for the RND generator, how cool was that [wakes up from a dream like state].
The reason for needed defined timing increments for myself were two fold, one for a visual aesthetic countdown clock, second and more importantly, having used a few older programs that worked fine on the original QL are difficult to use because of speed of emulators and different setups.
If I were to write a program that required actions to occur at a specific speed, not to fast not too slow, they would need appropriate timing attached to them in order to run more or less the same speed when used on diferent systems, hence the original question.
On a totally seperate note I found this website for the Compukit UK 101 http://home.micros.users.btopenworld.co ... uk101.html and also this for the ZX 80
http://home.micros.users.btopenworld.com/zx80/zx80.html, I still cannot remember what the other computer was though!
Memory jog - For those who remember the COMPUKIT UK 101 home built computer around the 1979, there was another similar computer system in kit form I seem to recall (but I could be wrong) that used the physical random noise generated by an open ended diode or transistor and used those signals for the RND generator, how cool was that [wakes up from a dream like state].
The reason for needed defined timing increments for myself were two fold, one for a visual aesthetic countdown clock, second and more importantly, having used a few older programs that worked fine on the original QL are difficult to use because of speed of emulators and different setups.
If I were to write a program that required actions to occur at a specific speed, not to fast not too slow, they would need appropriate timing attached to them in order to run more or less the same speed when used on diferent systems, hence the original question.
On a totally seperate note I found this website for the Compukit UK 101 http://home.micros.users.btopenworld.co ... uk101.html and also this for the ZX 80
http://home.micros.users.btopenworld.com/zx80/zx80.html, I still cannot remember what the other computer was though!
-----------------------------------------------------------------------------------
QLick here for the Back 2 the QL Blog http://backtotheql.blogspot.co.uk/
QLick here for the Back 2 the QL Blog http://backtotheql.blogspot.co.uk/
Re: Floating Point Numbers
Hmmm.
The only function available from basic going beyond a resolution of 1s is: PAUSE
This allows your program to wait in 20ms increments. Unfortunately, the wait time is interrupted by keyboard activity, so not of much use for interactive games.
For everything else, it seems you need to live with the 1s ticks of DATE or need to revert to machine code or BASIC extensions. Simon Goodwins TIMER extensions mentioned by Dilwyn would be a good starting point. It looks as if the QL, S*BASIC and its QDOS were not designed for CPU clock independence and interactive gaming
Cheers,
Tobias
The only function available from basic going beyond a resolution of 1s is: PAUSE
This allows your program to wait in 20ms increments. Unfortunately, the wait time is interrupted by keyboard activity, so not of much use for interactive games.
For everything else, it seems you need to live with the 1s ticks of DATE or need to revert to machine code or BASIC extensions. Simon Goodwins TIMER extensions mentioned by Dilwyn would be a good starting point. It looks as if the QL, S*BASIC and its QDOS were not designed for CPU clock independence and interactive gaming

Cheers,
Tobias
ʎɐqǝ ɯoɹɟ ǝq oʇ ƃuᴉoƃ ʇou sᴉ pɹɐoqʎǝʞ ʇxǝu ʎɯ 'ɹɐǝp ɥO
Re: Floating Point Numbers
Here we have to my opinion, two subjects of confusion :
1/ how does the "original QL" floating point engine work ?
2/ what does the "original QL" RND function exactly do ?
2> It is said that without any parameter, the RND function returns an "unpredictable" floating point number in the range 0.0 to 1.0 . One could guess that in fact, it generates some kind of periodic sequence of (16bit ? 32bit ? ...?) integers that are then scaled down to this floating point range. What is the period of this sequence ? 2**16 ? 2**32 ? ...? signed ? unsigned ? the "seeding" by use of the RANDOMISE command should behave accordingly ! allowing either a 16bit or a 32bit or a ... parameter ? integer ? floating point ? in what range ? signed ? unsigned ?
1> I will try to probe into the QL floating point engine through my ComputerOne FORTH floating point extensions package, that apparently are plain entry points to this engine, AND because FORTH is intrinsically an integer virtual machine, letting see exactly how this d...d "floating point" is actually formatted. Should be specific... Sinclairwise ?
Bye, Paul (now apparently chuggy microdrive : let's celebrate...)
1/ how does the "original QL" floating point engine work ?
2/ what does the "original QL" RND function exactly do ?
2> It is said that without any parameter, the RND function returns an "unpredictable" floating point number in the range 0.0 to 1.0 . One could guess that in fact, it generates some kind of periodic sequence of (16bit ? 32bit ? ...?) integers that are then scaled down to this floating point range. What is the period of this sequence ? 2**16 ? 2**32 ? ...? signed ? unsigned ? the "seeding" by use of the RANDOMISE command should behave accordingly ! allowing either a 16bit or a 32bit or a ... parameter ? integer ? floating point ? in what range ? signed ? unsigned ?
1> I will try to probe into the QL floating point engine through my ComputerOne FORTH floating point extensions package, that apparently are plain entry points to this engine, AND because FORTH is intrinsically an integer virtual machine, letting see exactly how this d...d "floating point" is actually formatted. Should be specific... Sinclairwise ?

Bye, Paul (now apparently chuggy microdrive : let's celebrate...)
May the FORTH be with you !
POLKa
POLKa
Re: Floating Point Numbers
I coded these few FORTH words to probe into the QL floating point format, and found interesting things...
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" :
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# ).
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
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 ;
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)
Code: Select all
F# 1.0 .Q
08 01 40 00 00 00 1 ok
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
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
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
May the FORTH be with you !
POLKa
POLKa
- Mr_Navigator
- QL Fanatic
- Posts: 782
- Joined: Mon Dec 13, 2010 11:17 pm
- Location: UK, Essex
- Contact:
Re: Floating Point Numbers
Ok, well thanks guys, I got a bit lost amongst the 1s and 0s, however I think I will have a play around with the TIMING command at the weekend and see what comes up.
Update:
BTW, this is what I was trying to emulate in the QL
http://www.online-stopwatch.com/full-screen-stopwatch/
Update:
BTW, this is what I was trying to emulate in the QL
http://www.online-stopwatch.com/full-screen-stopwatch/
-----------------------------------------------------------------------------------
QLick here for the Back 2 the QL Blog http://backtotheql.blogspot.co.uk/
QLick here for the Back 2 the QL Blog http://backtotheql.blogspot.co.uk/
Re: Floating Point Numbers
Ah, now I see what you mean.Mr_Navigator wrote:Ok, well thanks guys, I got a bit lost amongst the 1s and 0s, however I think I will have a play around with the TIMING command at the weekend and see what comes up.
Update:
BTW, this is what I was trying to emulate in the QL
http://www.online-stopwatch.com/full-screen-stopwatch/
If you want large text, I can send you a copy of my Enlarge routine for printing large characters on the screen.
There are several ways of approaching the "millisecond" counter. As the screen will only refresh up to 50 times per second, a 1/50 second counter for the fast units could be done with a routine like
FOR a = 1 TO 50 : AT y,x : PRINT a; : PAUSE 1
If you really wanted a very fast counter, you could use just a simple FOR...END FOR loop to print random numbers so fast you couldn't really see them. Or another possibility is that before your counter starts, you could probably do a speed test to see approximately how many FOR...END FOR iterations per second on the system the program is running on, e.g. this one counts how many in about 10 seconds:
time=date
FOR loop=1 TO (very large number)
AT y,x:PRINT 0; :REM for timing purposes, and use red on red or black on black to hide it
IF DATE > (time+9) THEN loopspersecond=loop : EXIT loop
END FOR loop
The variable loopspersecond now gives a rough idea of how many FOR/END FOR loops can be executed in a second and you can then divide it for an approximation of how many in whatever units you want. It will only ever be approximate (and very approximate at that) but for what you want to do it may be good enough, perhaps.
All the loop does is execute a continuous FOR loop printing (invisibly) a number to emulate what you'll be printing for timing purposes, and once ten seonds have passed it remembers how many loops it managed to do. Obviously, adjust to suit your program.
Dilwyn
--
All things QL - https://dilwyn.theqlforum.com
All things QL - https://dilwyn.theqlforum.com
Re: Floating Point Numbers
Wouldn't this scheme only work if SuperBasic is the only job running ? Otherwise, I guess that other jobs may be stealing 1/50sec time slices ? same question for PAUSE 1 : normally it pauses the computer (actually the SuperBasic job) for at least one 1/50sec cycle, but actually may it not pause for longer ?
Would it be possible (to your opinion) to add a little counting code sequence linked directly into the Qdos scheduler, which for sure ticks every 1/50sec ? If so, I think it would be the best timer practical...
Paul
Would it be possible (to your opinion) to add a little counting code sequence linked directly into the Qdos scheduler, which for sure ticks every 1/50sec ? If so, I think it would be the best timer practical...
Paul
May the FORTH be with you !
POLKa
POLKa