Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Inconsistency in RND
#1
If I write this simple program:
Code:
DIM u as UBYTE
10 let u =rnd*40
  print u
  pause 0
  if code inkey$=13 then stop
40 goto 10
a number between 0 and 40 will be shown at every pressing of ENTER.

However, inside of a larger program, this instruction:
Code:
DIM x AS UBYTE
...
x = rnd*40
always returns 38 when executed.

Also, the RND of the first example always returns exactly the same sequence when started afresh, at least under emulation (Spectaculator): 9, 34, 15, 7, 16, 25, 13, 37, 7, 24, 19 etc.

In the past I used a simple routine (by John Connolly) to generate random numbers. Here it is, modified to let it return values from 0 to 31:
Code:
LD A,R
AND %00011111
LD (address),A
When placed in a ZX-Basic listing as a subroutine, it will always return the first value. The only way to make it work is to assemble it elsewhere and call it from within ZX-BASIC with the usual RANDOMIZE USR call, then assign the PEEK [address] to a variable.
Reply
#2
Alessandro Wrote:If I write this simple program:
Code:
DIM u as UBYTE
10 let u =rnd*40
  print u
  pause 0
  if code inkey$=13 then stop
40 goto 10
a number between 0 and 40 will be shown at every pressing of ENTER.

However, inside of a larger program, this instruction:
Code:
DIM x AS UBYTE
...
x = rnd*40
always returns 38 when executed.
This might be a bug. Please provide me some code (you can do it privately, if you want). Also keep in mind that memory address 23670 and 23671 (ROM SEED variable) is also used by ZX Basic, so if something is accidentally writing there it will cause the RND sequence to repeat.
Quote:Also, the RND of the first example always returns exactly the same sequence when started afresh, at least under emulation (Spectaculator): 9, 34, 15, 7, 16, 25, 13, 37, 7, 24, 19 etc.
That's to be expected. You have to RANDOMIZE the sequence first. Use RANDOMIZE to have a different sequence each time. Since RANDOMIZE uses the system ROM timer ensure (within an emulator) that the time the program starts is always different. A trick is to ask the user to press a key before randomize, or doing it during the program main menu.
Quote:In the past I used a simple routine (by John Connolly) to generate random numbers. Here it is, modified to let it return values from 0 to 31:
Code:
LD A,R
AND %00011111
LD (address),A
When placed in a ZX-Basic listing as a subroutine, it will always return the first value. The only way to make it work is to assemble it elsewhere and call it from within ZX-BASIC with the usual RANDOMIZE USR call, then assign the PEEK [address] to a variable.
When using asm as a function, you should use FASTCALL to inline return a register. Try this:
Code:
FUNCTION FASTCALL myRND As Byte
   Asm
   ld a, r
   and 0x1F
   End Asm
END FUNCTION
Now call if with myRND (i.e. PRINT myRND).
Please tell me if this helps.
Reply
#3
Unfortunately it does not work. I wrote this simple program (prova.bas):
Code:
for n = 1 TO 20
  print at 2,0; myRND; ",";
  next n
  
  stop  

FUNCTION FASTCALL myRND As Byte
   Asm
   ld a, r
   and 0x1F
   End Asm
END FUNCTION

but at the moment of compiling it, here is the result:

prova.bas:1: warning: Using default implicit type 'float' for 'myRND'
prova.bas:9: identifier 'myRND' is a var, not a function
prova.bas:9: 'myRND' already declared as a var at 1

To make it work, I must insert the Assembly code into a subroutine:
Code:
10  myRND()
  print peek 49152; ",";

  pause 0
  
  if code inkey$=13 then goto 10

  stop  

sub myRND()
   Asm
   ld a, r
   and 0x1F
   LD (49152),A
   End Asm
end sub

This will produce the desired effect.
Reply
#4
Alessandro Wrote:Unfortunately it does not work. I wrote this simple program (prova.bas):
Code:
for n = 1 TO 20
  print at 2,0; myRND; ",";
  next n
  
  stop  

FUNCTION FASTCALL myRND As Byte
   Asm
   ld a, r
   and 0x1F
   End Asm
END FUNCTION

but at the moment of compiling it, here is the result:

prova.bas:1: warning: Using default implicit type 'float' for 'myRND'
prova.bas:9: identifier 'myRND' is a var, not a function
prova.bas:9: 'myRND' already declared as a var at 1

You have to declare the function *before* it's being used. Put the function before the code that invokes it; try and tell me. Rolleyes
Reply
#5
Thank you, now it works Big Grin

On a side note, I thought that functions, being a kind of subroutines (at least that's what I read in the Wiki) should be put at the end of the code, as it was normal with subroutines. (I never mastered the use of functions in Sinclair BASIC to be honest.)
Reply
#6
Alessandro Wrote:Thank you, now it works Big Grin

On a side note, I thought that functions, being a kind of subroutines (at least that's what I read in the Wiki) should be put at the end of the code, as it was normal with subroutines. (I never mastered the use of functions in Sinclair BASIC to be honest.)

If you need to call a function before implementing it, you can also pre-declare a function (like in C), using DECLARE, followed by the function header:
Code:
DECLARE FUNCTION FASTCALL myRND as Byte

  for n = 1 TO 20
  print at 2,0; myRND; ",";
  next n
  
  stop

FUNCTION FASTCALL myRND As Byte
   Asm
   ld a, r
   and 0x1F
   End Asm
END FUNCTION
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)