Spherical forums

Sphere Development => Sphere Support => Script Support => Topic started by: williammah on July 06, 2013, 02:24:12 pm

Title: Avoiding zeroes when generating random numbers
Post by: williammah on July 06, 2013, 02:24:12 pm
when using
Code: (javascript) [Select]
var damage = Math.floor(Math.random()*6); 

for example,

zero also comes up sometimes, is there anyway to get rid of it? Cos' getting zero for damage kinda sucks :P

Edit: fixed JS tags - radnen
Title: Re: Avoiding zeroes when generating random numbers
Post by: alpha123 on July 06, 2013, 02:46:38 pm
Code: (javascript) [Select]
var damage = 1 + Math.floor(Math.random() * 5); // Generate a number `n` such that  0 <= n <= 4 but then add 1 to it

Code: (javascript) [Select]
var damage = Math.max(1, Math.floor(Math.random() * 6)); // Pick the larger of 1 and a number `n` (0 <= n <= 5)

Code: (javascript) [Select]
var damage = Math.floor(Math.random() * 6) || 1; // 0 is false, so if the random number is 0 that will be `0 || 1` which is 1


Take your pick.
Title: Re: Avoiding zeroes when generating random numbers
Post by: N E O on July 06, 2013, 10:39:46 pm
In all fairness I'd likely only recommend alpha123's first code block since the second and third weigh it so it's twice as likely to pick 1.
Title: Re: Avoiding zeroes when generating random numbers
Post by: alpha123 on July 07, 2013, 01:16:44 am

In all fairness I'd likely only recommend alpha123's first code block since the second and third weigh it so it's twice as likely to pick 1.

Ah, that's true - I didn't think about that. Definitely the first one then.

Too bad Math.ceil(Math.random() * 5) won't work since Math.random() spec'ed to return n where 0 <= n < 1 (http://es5.github.io/#x15.8.2.14).
Although
Code: (javascript) [Select]
var damage = Math.ceil(Math.random() * 5) || 1;
will work. :)
Bah, never mind - that suffers the same bias as the 2nd and 3rd solutions. :/
Title: Re: Avoiding zeroes when generating random numbers
Post by: Radnen on July 07, 2013, 01:58:05 am
It's spec'd to return 0 <= n <= 1 that because it's impossible to get a 0 or 1 with a LCRNG, the excersise is left to the reader. :P
Title: Re: Avoiding zeroes when generating random numbers
Post by: Flying Jester on July 07, 2013, 03:45:15 pm

Code: (javascript) [Select]
var damage = 1 + Math.floor(Math.random() * 5); // Generate a number `n` such that  0 <= n <= 4 but then add 1 to it



I always thought that was the standard solution, anyway.

On the other hand, if you are using this for a damage calculation, perhaps having a double weight on a result of 1 wouldn't be a bad thing. It would be a single point of pity-damage, without changing the rest of the distribution. Well, it all depends on what you are trying to do.
Title: Re: Avoiding zeroes when generating random numbers
Post by: alpha123 on July 07, 2013, 05:35:56 pm

It's spec'd to return 0 <= n <= 1 that because it's impossible to get a 0 or 1 with a LCRNG, the excersise is left to the reader. :P

That's 0 <= n < 1, but the spec does not care how it's implemented. SpiderMonkey and I believe V8 happen to use LCRNGs, but that's an implementation detail and you shouldn't rely on that. However if that is the case (I don't know much about pseudorandom number generation, so I'll take your word for it) Math.ceil(Math.random() * 5) would work, correct?
Title: Re: Avoiding zeroes when generating random numbers
Post by: Radnen on July 07, 2013, 05:40:53 pm
Oops, yeah you are right. 0 <= n < 1 Silly me, :)

Quick-Soure:
http://en.wikipedia.org/wiki/Linear_congruential_generator
Title: Re: Avoiding zeroes when generating random numbers
Post by: Fat Cerberus on July 07, 2013, 07:10:38 pm

However if that is the case (I don't know much about pseudorandom number generation, so I'll take your word for it) Math.ceil(Math.random() * 5) would work, correct?


It's been my understanding that you should always implement ranged randoms using floor, regardless of the actual range you need.  Supposedly using either round or ceil will skew the distribution to something other than uniform.

However, there's another caveat: Regardless of whether you use floor, ceil or round, due to floating point rounding issues, there's a very small chance (something on the order of 1 in 2^60 IIRC) that you could get a number one higher than your upper bound.  For that reason, this is the method I use:

Code: (javascript) [Select]
var rnd = low + Math.min(Math.floor(Math.random() * (high - low + 1)), high)
Title: Re: Avoiding zeroes when generating random numbers
Post by: Flying Jester on July 07, 2013, 09:09:05 pm

However, there's another caveat: Regardless of whether you use floor, ceil or round, due to floating point rounding issues, there's a very small chance (something on the order of 1 in 2^60 IIRC) that you could get a number one higher than your upper bound.  For that reason, this is the method I use:

Code: (javascript) [Select]
var rnd = low + Math.min(Math.floor(Math.random() * (high - low + 1)), high)



Are you sure this applies to JS?

Also, 2^60 is such a small chance (really, really small...) that I wouldn't even bother with that. There's also a chance that HDD errors will corrupt your source code and make the high range one integer higher, that the CPU or RAM will have a hard error (unless you have ECC memory, then there would also have to be an ECC error, which is still possible) and produce a garbage result somewhere, etc. ...I don't think it's really worth putting that into your code.
Title: Re: Avoiding zeroes when generating random numbers
Post by: Fat Cerberus on July 07, 2013, 10:04:26 pm
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random

From the top of the Examples section: "Note that as numbers in JavaScript are IEEE 754 floating point numbers with round-to-nearest-even behavior, these ranges, excluding the one for Math.random() itself, aren't exact, and depending on the bounds it's possible in extremely rare cases (on the order of 1 in 2^62) to calculate the usually-excluded upper bound."

Considering that in certain scenarios in Specs (enemy AI, notably, when choosing a random move), I'm using the generated number to index into an array, I figure the extra min() call can't hurt.
Title: Re: Avoiding zeroes when generating random numbers
Post by: Flying Jester on July 07, 2013, 10:13:19 pm
Fair enough. But if I put that into a game, I might be tempted to just let the player instantly win the battle if they got lucky on the order of 1/(2^62)!
Title: Re: Avoiding zeroes when generating random numbers
Post by: Fat Cerberus on July 08, 2013, 12:02:13 am
I'm thorough, what can I say. :)  If it's a bug I can prevent without much effort, I'll account for it.  In fact, the smaller the (nonzero) odds of something like this occurring, the more likely I am to account for it.  Try to reduce the "sufficiently advanced machine" factor, you know?