diff --git a/compiler/res/prog8lib/math.p8 b/compiler/res/prog8lib/math.p8 index 15469f79b..646b089cb 100644 --- a/compiler/res/prog8lib/math.p8 +++ b/compiler/res/prog8lib/math.p8 @@ -75,7 +75,7 @@ _sinecosR8 .char trunc(127.0 * sin(range(180+45) * rad(360.0/180.0))) }} } - asmsub rnd() -> ubyte @A { + asmsub rnd() clobbers(Y) -> ubyte @A { %asm {{ jmp math.randbyte }} @@ -87,6 +87,24 @@ _sinecosR8 .char trunc(127.0 * sin(range(180+45) * rad(360.0/180.0))) }} } + sub randrange(ubyte n) -> ubyte { + ; -- return random number uniformly distributed from 0 to n-1 (compensates for divisibility bias) + cx16.r0H = 255 / n * n + do { + cx16.r0L = math.rnd() + } until cx16.r0L < cx16.r0H + return cx16.r0L % n + } + + sub randrangew(uword n) -> uword { + ; -- return random number uniformly distributed from 0 to n-1 (compensates for divisibility bias) + cx16.r1 = 65535 / n * n + do { + cx16.r0 = math.rndw() + } until cx16.r0 < cx16.r1 + return cx16.r0 % n + } + asmsub rndseed(uword seed1 @AY, uword seed2 @R0) clobbers(A,Y) { ; -- set new pseudo RNG's seed values. Defaults are: $00c2, $1137 %asm {{ diff --git a/compiler/res/prog8lib/virtual/math.p8 b/compiler/res/prog8lib/virtual/math.p8 index 194c30187..96df9db72 100644 --- a/compiler/res/prog8lib/virtual/math.p8 +++ b/compiler/res/prog8lib/virtual/math.p8 @@ -176,6 +176,24 @@ math { }} } + sub randrange(ubyte n) -> ubyte { + ; -- return random number uniformly distributed from 0 to n-1 (compensates for divisibility bias) + cx16.r0H = 255 / n * n + do { + cx16.r0L = math.rnd() + } until cx16.r0L < cx16.r0H + return cx16.r0L % n + } + + sub randrangew(uword n) -> uword { + ; -- return random number uniformly distributed from 0 to n-1 (compensates for divisibility bias) + cx16.r1 = 65535 / n * n + do { + cx16.r0 = math.rndw() + } until cx16.r0 < cx16.r1 + return cx16.r0 % n + } + sub rndseed(uword seed1, uword seed2) { ; -- reset the pseudo RNG's seed values. Defaults are: $a55a, $7653. %ir {{ diff --git a/docs/source/libraries.rst b/docs/source/libraries.rst index 13bb4c433..1c7e42051 100644 --- a/docs/source/libraries.rst +++ b/docs/source/libraries.rst @@ -458,6 +458,12 @@ but perhaps the provided ones can be of service too. ``rndw ()`` Returns next random word 0-65535 from the pseudo-RNG sequence. +``randrange (ubyte n) -> ubyte`` + Returns random byte uniformly distributed from 0 to n-1 (compensates for divisibility bias) + +``randrangew (uword n) -> uword`` + Returns random word uniformly distributed from 0 to n-1 (compensates for divisibility bias) + ``rndseed (uword seed1, uword seed2)`` Sets a new seed for the pseudo-RNG sequence (both rnd and rndw). The seed consists of two words. Do not use zeros for the seed! diff --git a/examples/test.p8 b/examples/test.p8 index 9a95c9161..0f88713e0 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,25 +1,43 @@ %import textio -%import string - +%import math %zeropage basicsafe %option no_sysinit main { - sub start() { - screen.text_colors = [6,5,4,3,2,1] + uword[7] rolls - for cx16.r0L in screen.text_colors { + txt.print("wait...\n") + repeat 30 { + repeat 1000 { + unroll 10 rolls[math.rnd() % len(rolls)]++ + } + } + + for cx16.r0L in 0 to len(rolls)-1 { txt.print_ub(cx16.r0L) txt.spc() + txt.print_uw(rolls[cx16.r0L]) + txt.nl() + } + + txt.print("wait...\n") + rolls = [0,0,0,0,0,0,0] + repeat 30 { + repeat 1000 { + unroll 10 rolls[math.randrange(len(rolls))]++ + } + } + + for cx16.r0L in 0 to len(rolls)-1 { + txt.print_ub(cx16.r0L) + txt.spc() + txt.print_uw(rolls[cx16.r0L]) + txt.nl() } - txt.nl() } } -screen { - ubyte[6] text_colors -} /*main222 { sub start() {