Rand statement Int range
Blitz3D Forums/Blitz3D Programming/Rand statement Int range
| ||
In the docs for the CreateBank() command, the following example is given:; Bank Commands Example ; --------------------- bnkTest=CreateBank(12) PokeByte bnkTest,0,Rand(255) PokeShort bnkTest,1,Rand(65535) PokeInt bnkTest,3,Rand(-2147483648,2147483647) PokeFloat bnkTest,7,0.5 Print PeekByte(bnkTest,0) Print PeekShort(bnkTest,1) Print PeekInt(bnkTest,3) Print PeekFloat(bnkTest,7) FreeBank bnkTest I have found that the result of the PokeInt command as stated will always produce the minimum value in the Rand statement, -2147483648, and in fact that same Rand statement by itself produces that result. But that is the range of a four byte int, so why is that the case? Even stranger, the command Print Rand(-2147483645,2147483647) produces -2147483646, which is outside the range given. Finally, this code: Graphics3D(1024,768,32,2) For min=-2147483648 To 0 val=Rand(min,2147483647) Print "Rand("+min+",2147483647): "+val While KeyDown(57) Delay(1) Wend If KeyHit(1) Then End Next similarly produces results further and further outside the range. Also, is it just my machine that produces these results? Thanks. |
| ||
Mines not producting anything under -2147483645 with that last code snippet. |
| ||
Also, is it just my machine that produces these results? It's not just you. I think the fundamental problem is that Blitz3D runs with the floating point unit set to single precision mode. Internally, the random number generator uses double precision arithmetic. But with the FPU in single precision mode the calculations still have only 24-bit accuracy, about 7 decimal digits. Print Rand(-2147483648, 2147483647) covers the full range of 32-bit integer values, so it would need 32-bit precision to work correctly. A much smaller range, such as Rand(-2147483648,-2147400000), should not be a problem. |
| ||
Thanks for the responses. I had just never before seen a command specifically listed in the documentation that does not work. Floyd, your analysis may be correct, although that command gave the same result. I was originally toying with this: If the Rand() is using an int as a seed, and it produces an int for its result, then there logically should be a one-to-one pairing of a seed to a result. (assuming you use the full Int range of possible results.) Unless... two seeds sometimes produce the same result. Of course, since it's just a formula that has to be possible. In which case there must be some results than cannot be generated. Hardly seems fair, really. |
| ||
Here's a test with a range ( one billion ) which is much too big for 24-bit arithmetic.; Generate random integers up to 10^9, keep track of the ones up to 10^5. ; Each number has probability 1/10^4 of being that small. So with 10^7 ; numbers generated we expect about 10^3 to be small, i.e. up to 10^5. ; ; This test shows about a thousand such results, as expected. ; But they should be randomly scattered among 1 to 100000. ; Instead there are only seven different values. Dim count(100000) For n = 1 To 10000000 r = Rand( 1, 1000000000 ) If r <= 100000 Then count( r ) = count( r ) + 1 Next Print Print " Rand count" Print ; Show the counts only for numbers that actually occurred, meaning count(n) > 0. For n = 1 To 100000 If count(n) <> 0 Print RSet( n, 6 ) + RSet( count( n ), 10 ) End If Next WaitKey Here is the output with Blitz3D: Rand count 7630 168 22889 142 38147 147 53406 127 68665 163 83924 150 99183 114 And in BlitzPlus, but only showing numbers up to 1000: Rand count 8 1 187 2 209 1 299 1 381 1 649 1 776 1 969 1 This suggests the random number generators in Blitz3D and BlitzPlus are radically different. I have no idea why. |
| ||
That's very interesting. For most game purposes at low ranges the randomizer would be fine, but that's a major caveat for doing anything serious. Thanks. |
| ||
Here's an update to this. The following code generates 1 million ints from 0 to 1 million, and keeps track of how many times each is generated in an array. Exactly 934464 values (93%) do not get picked. It then adds another million values and lo and behold, the exact same 934464 values have still not been picked. It then continues to add a million values to the array at a time and the randomizer only selects from the same 7% of possible values. Note that 1 million is well within the 24 bit range of 16,777,215 ints. Graphics3D(1024,768,32,2) Global maxArray=1000000 Global numRuns=1000000 Global sumRuns# Dim v(maxArray) Local i While Not KeyHit(1) AddValues() Print CountEmpties()+" have not been generated in "+sumRuns+" values. +"+100.0*CountEmpties()/maxArray+"%" Wend WaitKey() End Function CountEmpties() Local i, count For i=0 To maxArray-1 If v(i)=0 Then count=count+1;:Print i Next Return count End Function Function AddValues() ;SeedRnd(MilliSecs()) Local i,value For i=0 To numRuns-1 value=Rand(maxArray) v(value)=v(value)+1 Next sumRuns=sumRuns+numRuns End Function |
| ||
If 934464 values are not picked then 1000000 - 934464 = 65536 are. So Blitz3D is for some unknown reason using 16-bit values. Maybe it's using the random number generator in C/C++, which I think is 16-bit. If you know a little calculus and probability you can estimate how many values will be missed. A randomly selected integer 1..N has probably 1/N of being chosen in a single trial. It has probability 1-1/N of not being chosen in one trial, and probability (1-1/N)^N of being missed every time in N trials. As N becomes very large (1-1/N)^N approaches the limiting value Exp(-1). The expected number of missed values when N is a million is thus about 1000000*Exp(-1), which is 367879. Sure enough, if I run your test in BlitzPlus I get 367959, very close to the predicted value. |
| ||
I ran into this as well, when attempting to factor "random" int values. The Rand(0, 2147483646) never returns a prime above 16384 aka 2^14. Instead, for any value over 16383 the Rand() function returns pseudorandom number less than 16384 multiplied by a power of 2. My temporary workaround was: Function Random%() rtn1=Rand%(16383) Shl 18 rtn2=Rand%(16383) Shl 11 rtn3=Rand%(16383) Return rtn1 Xor rtn2 Xor rtn3 End Function |
| ||
Genius. Floyd for the cause, Subirenihil for the solution. Thank you both. |
| ||
There is this old topic by me (7 months ago) on generating random numbers. I think in my version there is no repetition until the entire cycle repeats, and also, all 32 bit unsigned values are represented, (with nothing skipped). Random Numbers [using CRC logic] http://www.blitzbasic.com/Community/posts.php?topic=100055 Trinosis included a revision for positive numbers as well. Using 32 bits allows for 4,294,967,296 unique numbers. Using 31 bits allows for 2,147,483,648 unique numbers. |