question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Using seed breaks .integer

See original GitHub issue

I’m using 1.0.18. Reproduce with this: new Chance(Math.random()).integer({min:1,max:3}) This returns a value of 2 100% of the time.

Issue Analytics

  • State:open
  • Created 4 years ago
  • Comments:6 (5 by maintainers)

github_iconTop GitHub Comments

2reactions
somejeffcommented, Apr 22, 2022

Hey @gerardolima, here’s my feedback as to why Math.random() as a seed isn’t optimal, but also technically supported.

TL;DR: The built-in MersenneTwister takes the seed, unsigned right shifted, and goes from there. Anything between 0 and 1 becomes 0.


The built-in MersenneTwister uses the seed to populate an array of pseudorandom numbers. It’s expecting a seed between 0 and 10_000_000_000_000

Let’s pick a number from 1 to 10, using seeds 0 to 4.

new Chance(0).integer({min:1,max:10})
Seed First few elements of the array First call to mt.random() to choose an int Result
0 [0, 1, 1812433255, ...] 0.548813502304256 6
1 [1, 1812433254, ...] 0.4170219984371215 5
2 [2, 3624866507, ...] 0.43599490262567997 5
3 [3, 1142332464, ...] 0.5507979043759406 6
4 [4, 2954765717, ...] 0.9670298383571208 10

Initializing the MT with such close integers and only providing a field of 1-10 for integer() to choose (once), returns 6,5,5,10.


Narrow the field to {min:1,max:3} is like shrinking the dart board down to only 3 options.

new Chance(0).integer({min:1,max:3})
Seed First few elements of the array First call to mt.random() to choose an int Result
0 [0, 1, 1812433255, ...] 0.548813502304256 2
1 [1, 1812433254, ...] 0.4170219984371215 2
2 [2, 3624866507, ...] 0.43599490262567997 2
3 [3, 1142332464, ...] 0.5507979043759406 2
4 [4, 2954765717, ...] 0.9670298383571208 3

Let’s see what happens if you pass a seed between 0 and 1, essentially populating the array with zero as the first entry and always returning the same pseudorandom value.

new Chance(0.x).integer({min:1,max:10})
Seed First few elements of the array First call to mt.random() to choose an int Result
0 [0, 1, 1812433255, ...] 0.548813502304256 6
0.1 [0, 1, 1812433255, ...] 0.548813502304256 6
0.2 [0, 1, 1812433255, ...] 0.548813502304256 6
0.3 [0, 1, 1812433255, ...] 0.548813502304256 6
0.4 [0, 1, 1812433255, ...] 0.548813502304256 6
0.5 [0, 1, 1812433255, ...] 0.548813502304256 6
0.6 [0, 1, 1812433255, ...] 0.548813502304256 6
0.7 [0, 1, 1812433255, ...] 0.548813502304256 6
0.8 [0, 1, 1812433255, ...] 0.548813502304256 6
0.9 [0, 1, 1812433255, ...] 0.548813502304256 6
0.99999999 [0, 1, 1812433255, ...] 0.548813502304256 6
1 [1, 1812433254, ...] 0.4170219984371215 5

The same would apply to {min:1,max:3} and always return 2.


Could the MersenneTwister be improved to support real numbers between 0 and 1 instead of ints?
Sure, but any change to the twister is a breaking change for all those expecting patterns from their fixed seeds.

Could the constructor validate and reject real numbers? Also a breaking change for those passing a real number with a larger field, such as: new Chance(Math.random()*10_000_000_000_000);

String seeds? If a String is passed, it’s converted into an integer using each letter of the string. 😐


Recommendation?

Take advantage of the full 32 bits for a seed and stay away from 0 -> 1 and the other limit too:

new Chance(Math.random() * Infinity);  // https://xkcd.com/221/
0reactions
gerardolimacommented, Apr 26, 2022

hey again, @somejeff, I understand your explanation and I agree that keeping a stable interface is precious for any library.

My comment was about improving the ergonomics of the API by avoiding what looks to be a rather silly, but also one easy mistake to make. As a suggestion, Chance could trigger an error when seed % 1 !== 0 or maybe being even more explicit, when 0 < seed < 1, which is the range of Math.random(). If throwing an error should sound too much, maybe log a warning on console?

That said, I understand that this might break the behaviour in some cases – and maybe unfold some unintended usage of Chance(Math.random()) – so it’s a balance and it’s obviously your call. Thank you for your good work!

Read more comments on GitHub >

github_iconTop Results From Across the Web

random.seed(): What does it do? - Stack Overflow
Pseudo-random number generators work by performing some operation on a value. Generally this value is the previous number generated by the generator.
Read more >
Numpy Random Seed, Explained - Sharp Sight
In this tutorial, I'll explain how to use the NumPy random seed function, which is also called np.random.seed or numpy.random.seed.
Read more >
Randomizing should be easy, right? oh, well, maybe not..
srand() takes an integer, so something like $seed = rand(); srand($seed) would always lead to seeding the prng with 0, not good at...
Read more >
Random number generator seed mistakes
Stories of projects that have made mistakes seeding a random number generator and better ways to do it.
Read more >
Challenge 22: Crack an MT19937 seed - GitLab
Make sure your MT19937 accepts an integer seed value. Test it (verify that you're getting the same sequence of outputs given a seed)....
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found