X-platform random numbers

Monkey Forums/Monkey Programming/X-platform random numbers

impixi(Posted 2014) [#1]
Given the same Seed value, does Monkey generate the same sequence of random numbers regardless of target, OS, and hardware platform?

Looks like it *almost* does (for X-target on same hardware, at least), except for the representation of floating point numbers issue.

Can some of you run the following code and let me know if your results match up with mine?
Strict

Function Main:Int()

	Seed = 1000

	For local n := 1 To 10
		Print Rnd(0, 100)
	Next

	Return 0
End


My results:

HTML:

62.36203908920288
98.23320508003235
52.78060436248779
68.4232771396637
85.03351211547852
33.26745629310608
38.07581663131714
79.29973602294922
22.291147708892822
3.0291080474853516



C++ Tool:

62.362039089202881
98.233205080032349
52.780604362487793
68.423277139663696
85.033512115478516
33.267456293106079
38.075816631317139
79.299736022949219
22.291147708892822
3.0291080474853516



GLFW2 and GLFW3:

62.362037658691406
98.233207702636719
52.780605316162109
68.42327880859375
85.03350830078125
33.2674560546875
38.075817108154297
79.299736022949219
22.291147232055664
3.0291080474853516



(Desktop PC running Windows 8.1)

So this means if you wanted to procedurally generate a game level that is consistent across multiple targets, you would use only the integer portion of the generated numbers in your calculations?


Raph(Posted 2014) [#2]
I have had consistent results using integers across Android, iOS, HTML5, Flash, PC, and Mac.


impixi(Posted 2014) [#3]
Okay, thanks Raph.


dawlane(Posted 2014) [#4]
Intel i7 running 64 bit Linux
C++
62.362039089202881
98.233205080032349
52.780604362487793
68.423277139663696
85.033512115478516
33.267456293106079
38.075816631317139
79.299736022949219
22.291147708892822
3.0291080474853516

GLFW
62.362037658691406
98.233207702636719
52.780605316162109
68.42327880859375
85.03350830078125
33.2674560546875
38.075817108154297
79.299736022949219
22.291147232055664
3.0291080474853516

HTML
62.36203908920288
98.23320508003235
52.78060436248779
68.4232771396637
85.03351211547852
33.26745629310608
38.07581663131714
79.29973602294922
22.291147708892822
3.0291080474853516

With out more testing. I would say that at float consistency would be that same for at least 3 or 4 digits for the factional part.


Gerry Quinn(Posted 2014) [#5]
It's looking like the platforms are storing the numbers in an identical fashion, but printing them out differently! At least that's the only explanation I can think of, because if the actual values differed, surely the difference would rapidly be amplified until the results were completely different?

Years ago I wrote an integer rand() function that emulates MSVC rand(), so if you are worried you could consider using it:
http://www.monkey-x.com/Community/posts.php?topic=1568


impixi(Posted 2014) [#6]
Thanks dawlane. Just to be extra cautious, I'd use the integer portion only, none of the fractional...

Gerry, you may be correct... I'm not sure what Monkey uses for its algorithm (I haven't looked into the source), but the industry standard seems to be http://en.wikipedia.org/wiki/Mersenne_twister. IIRC, Brucey coded a version of Mersenne Twister for BlitzMax ages ago... Could probably port that...


ElectricBoogaloo(Posted 2014) [#7]
Agreed.
A LOT of my games use seeded-randomisation to build levels and things. For the most part, I've not noticed any differences, but I tend to use mostly ints, and not delve too deep into the floating points. I'd say that you're pretty much safe to assume it's ok, and is "mostly" identical on all platforms, as long as you don't allow it to get "too" precise.

.. But then, if we're honest, even exact pre-determined numbers can get fuddled when monitored at such high precision. That's just one of those things we all have to be aware of. There are FAR worse things that can happen when dealing with multiple targets. .. (Stupid Android image dithering, breaking my data methods.. grrr..)


Floyd(Posted 2014) [#8]
At a glance the differences between platforms are roughly on the order of ("correct value")/(10^8). This suggests that the actual double precision values have been converted to single precision, then back to double.

I suppose it's related to issues raised in this old discussion: http://www.monkey-x.com/Community/posts.php?topic=1566&page=1


Floyd(Posted 2014) [#9]
if the actual values differed, surely the difference would rapidly be amplified until the results were completely different?


The random number generator produces a sequence of 32-bit integers. I believe JavaScript emulates this via double precision. But assuming it is done correctly there should be no difference between platforms.

These integer values are then massaged to produce values for Rnd(). That's where the differences arise.

Here's the source for monkey.random, from 75d. ( I'm not keeping up with developments. )

' Module monkey.random
'
' Placed into the public domain 24/02/2011.
' No warranty implied; use at your own risk.

Private

Const A=1664525
Const C=1013904223

Public

Global Seed=1234

'Note: Freaky '|0' below is a work around for Js not having a real int type.
'
'Should probably be & $ffffffff? Think about it later!
'
Function Rnd#()
	Seed=(Seed*A+C)|0
	Return Float(Seed Shr 8 & $ffffff)/$1000000
End

Function Rnd#( range# )
	Return Rnd()*range
End Function

Function Rnd#( low#,high# )
 	Return Rnd( high-low )+low
End



impixi(Posted 2014) [#10]
81b has the same source code. Thanks for your insight, Floyd.

Another thing I've noticed is if you want to seed with Millisecs() you need to explicitly import it from mojo.app. Not a problem for those of us with a Pro license, but for those who don't... Time to roll your own Millisecs() functions... ;)

EDIT: Actually, you have to create a proper Mojo app to make use of the Millisecs() function. This will NOT compile:

Strict

Import mojo.app

Function Main:Int()

	Seed = Millisecs()

	For Local n := 1 To 10
		Print Rnd()
	Next

	Return 0
End


A shame... Unless I'm overlooking something obvious...

.


Gerry Quinn(Posted 2014) [#11]
What has the Pro license got to do with it?

Unless people are using Monkey language without mojo for a wide variety of targets. Are they? In any case , the diddy module also has a Millisecs function, so if so, this should be the least of their troubles!


impixi(Posted 2014) [#12]
Heh, I just realized my example wasn't working because my target was set to "c++ tool". *facepalm*

@Gerry: You answered your own question. The Pro license gives you Mojo which gives you Millisecs(). So the Pro license has everything to do with that.

But I agree with your other points...


ImmutableOctet(SKNG)(Posted 2014) [#13]
The free version of Monkey already comes with the HTML5 and GLFW implementations of Mojo. This means it comes with the 'mojo.app' module, and therefore has 'Millisecs'. The version of Monkey you're running doesn't change the fact that Mojo only works on supported game-targets. So, the STDCPP / C++ Tool target doesn't come with it by default.

That being said, as Gerry Quinn mentioned, Diddy comes with its own implementation, from what I remember, anyway. I also made a module for this (Along with the old 'Delay' command).


impixi(Posted 2014) [#14]
The free version of Monkey already comes with the HTML5 and GLFW implementations of Mojo.


Well, there you go. That was not the case in the early Monkey/Mojo days. Today I learned I'm further behind the times than I thought! Apologies to Gerry...


... Mojo only works on supported game-targets. So, the STDCPP / C++ Tool target doesn't come with it by default.


That I *do* already know. Hence the *facepalm* at my foolishness trying to run the above code on that target. :)


Samah(Posted 2014) [#15]
Diddy has a RandomSource class that functions similarly to Java's Random class. It uses Monkey's built-in Rnd() function but with a bunch of helper methods and the ability to cache seeds.

Code:
https://code.google.com/p/diddy/source/browse/src/diddy/math.monkey

Sample:
https://code.google.com/p/diddy/source/browse/examples/RandomSource/testRandomSource.monkey