fwiw… if you truly need LOTS of seeds (say shuffling deck of cards, where 52! > 2^31) you might try the Mersenne Twister, it supports up to a ridiculous (2^32)^624 seeds, each with a ridiculous period of 2^19937. here is a pure lua implementation you could easily try out (use case: when “quality” is more important than “performance”) - it also has the benefit of passing the original author’s validation test (there are other lua implementation of MT out there too, but not all will pass validation – cuz the only thing worse than a PRNG with known flaws is a PRNG with unknown flaws! :D) hth
I’ve decided to just use os.time for the seed, perform half of the checks and then use os.time() to see again and do the other half.
That should be good enough in the event that 2 people start their app for the first time at exactly the same second.
In all honesty it doesn’t matter too much even if 2 users get the same numbers, I was just trying to make things as random as I could without impacting performance. Thanks for the help though everyone.
First, we are using Lua’s math library. I don’t believe we have made any changes to it. If I understand it correctly, we are just passing the value to the c library srand() ) function as a 32 bit unsigned integer. As Dave pointed out overflows result in bad seeds.
While I don’t know how much variance system.getTimer() is going to provide (the time from app start to your randomseed() call) will pretty much be the same on processors of the same speed) and the closer to the start of your app you put the randomseed() call the smaller that value and variance will be…) what you can do is use the bit plugin and shift the value of os.time() say four bits to the left and OR in the bottom 4 bits of system.getTimer(), as long as you’re getting a 32 bit unsigned int back from the bit plugin. Or replace the top four bits with the bottom 4 bits of system.getTimer().
Lua numbers are double floats, but it can represent whole numbers up to 53 bits (2^53) (please correct me if I’m wrong on this) which is way bigger than an unsigned 32 bit int (4,294,967,295). While that’s a 10 digit number, anything larger overflows. That is 4,294,967,296 is a 10 digit number, but it won’t fit in an unsigned 32 bit int.
Rob
Warning: I am answering this quickly and didn’t give a thorough read through, so if I’m repeating someone or off the target, my apologies.
When you call math.random() rapidly, you are likely to get a number of repeats, especially if you have a limited range to choose from:
print(math.random(1,32)) print(math.random(1,32)) print(math.random(1,32)) print(math.random(1,32)) print(math.random(1,32)) ... print(math.random(1,32))
You can solve this by using a shuffle bag instead.
I’ll let you look up what a shuffle bag is if you want more details, but …
think of it like a bag, that you fill with numbers, etc. which ensures you get a random selection and don’t repeat till you’ve pulled all the items out of the ‘bag’.
Here is an example and a module that should help:
http://github.com/roaminggamer/RG_FreeStuff/raw/master/AskEd/2016/07/shufflebag.zip
Run the example and click the red/green/cyan ‘buttons’ to select cards from the sample bags (see code).
To Ed’s repeating issue, its a core problem with using the C library’s rand() function. It’s notorious for generating repeating numbers when the range is small. Coin flips and 1-4’s are particularly problematic. Most Unix implementations now offer a random()/srandom() pair that eliminates the low range repeating. But random()/srandom() are not part of the standard C library, so Lua can’t depend on it’s availability.
There are plenty of alternate generators out there. In addition to Ed’s option, there is a community plugin: MWC Random Number Generator (https://store.coronalabs.com/plugin/mwc-random-number-generator) available as a plugin. And of course if you have network connectivity you could go to random.com and use network.request() to generate random numbers that are truly random. You could fetch one number from them to seed math.randomseed()!
Rob
Alan, the number is too big and it exceeds a 32-bit integer’s limit which is what math.seed() accepts as an argument. That’s the problem. And this is not really a 64-bit versus 32-bit environment problem either.
So, what’s happening here is that you’re concatenating two 32-bit numbers (os.time() and system.getTimer()) to a single 64-bit number in string form. When you call Lua’s tonumber() function, you’re turning that 64-bit integer string into a double precision float (Lua 5.1 does not support integers). A 64-bit number has 20 digits, but a double precision float has a precision of 15 digits (worst case), meaning that you’ll lose the 5 least significant digits in the number (these are the right-most digits) if all 20 digits are used. When you feed that double precision number to math.seed(), it gets converted to a 32-bit integer in the C language in both a 32-bit and 64-bit environment. A 32-bit integer won’t accept a value greater than 2,147,483,647 (ie: ((2^32)/2) - 1). Odds are extremely high that your double precision floating point value is larger than this limit. The C language standard states that casting a float to an integer that’s beyond its limits are undefined (see link below, section 6.3.1.4, bullet 2, last sentence).
http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf
And for your quick reference, here is a copy-and-paste of what is relevant in the above linked document.
If the value being converted is outside the range of values that can be represented, the behavior is undefined.
This means that the behavior will likely be different between different C compilers and environments. It may overflow (this might be happening on Mac). Or it may be set to the max int value (this may be happening on Android). In any case, the point is you can’t depend on this behavior. It’s undefined. Meaning that you should avoid it.
Bottom Line:
Don’t pass a number to math.seed() with a value greater than a 32-bit signed integer.
How’s that for an explanation? 
Thank you Joshua. As soon I actually thought about it, of course the number couldn’t be infinitely long!
Just one of those days…