[HN Gopher] There's Math.random(), and then there's Math.random(...
___________________________________________________________________
There's Math.random(), and then there's Math.random() (2015)
Author : beepill
Score : 114 points
Date : 2025-02-03 20:57 UTC (4 days ago)
(HTM) web link (v8.dev)
(TXT) w3m dump (v8.dev)
| gnabgib wrote:
| (2015) Discussion at the time (229 points, 106 comments)
| https://news.ycombinator.com/item?id=10751396
| dang wrote:
| Thanks! Macroexpanded:
|
| _There 's Math.random(), and then there's Math.random()
| (2015)_ - https://news.ycombinator.com/item?id=38188421 - Nov
| 2023 (49 comments)
|
| _There 's Math.random(), and then there's Math.random()_ -
| https://news.ycombinator.com/item?id=10751396 - Dec 2015 (106
| comments)
| maxloh wrote:
| I learned in college that most random number generators use the
| current timestamp to generate a pseudo-random number.
|
| How does this differ cryptographically from algorithms like
| MWC1616 and xorshift128+ in backend applications? How can a
| random number generator be vulnerable to attacks in real life?
|
| Does it really matter which random number generator you use on a
| webpage? It's already considered an insecure environment anyway
| (that's why we have server-side validation).
| tomsmeding wrote:
| In a class we had to reverse-engineer an application that had
| encrypted some text file -- we had to decrypt it without the
| key. Turned out the application just used the current unix
| timestamp as the key. A brute-force search of the past few
| months didn't take very long.
|
| If you include nanoseconds in your key then you have more
| entropy, of course, but timestamps are guessable, so it's
| risky.
| sverhagen wrote:
| Those nanoseconds aren't really entropy then, are they?
| lmm wrote:
| They're entropy for most practical purposes. But there's
| only 1000 possibilities, so that's less than 10 bits'
| worth.
| boothby wrote:
| Especially if you're writing a file, the creation time is
| a big hint! Even nanoseconds won't help if you're leaking
| that many bits from your seed.
| tomsmeding wrote:
| That's milliseconds; nanoseconds are 1e-9 seconds. Still,
| the file creation time remark of sibling is pertinent.
| hapidjus wrote:
| One attack might be exploiting One Time Passwords. Lets say you
| send yourself enough tokens to calculate the state, you will
| then be able to calculate the next token and login as another
| user. However that should be easily fixed by adding some salt
| relating to the user, meaning you would only be able to figure
| out _your_ next token.
| atoav wrote:
| You can go back into a time before computers and use the most
| famous examples of how bad RNGs endanger crypto: One Time Pads
| (OTP). This is basically just a XOR of your message with your
| random numbers. If your random numbers are bad they leave
| patterns in the XOR-ed message that can be statistically
| analyzed and potentially decrypted.
|
| Bad PRNGs repeat early and have predictable patterns, as such
| they form a special attack vector.
|
| Whether that is really an issue for any given application,
| depends on the application (e.g. how shortlived the crypto is
| and how bad decryption acter the fact is). But if you are
| asking that question it likely means you don't know enough
| knowledge to roll your own crypto unless you wanna be in a
| world of pain.
|
| Just because PRNGs appear unpredictable to you does not mean
| they aren't.
|
| If you really wanna go the route, at least add a salt, so
| something like
| Hash(application_secret_long_and_random +
| timestamp_nanosecond_precision)
| masklinn wrote:
| > I learned in college that most random number generators use
| the current timestamp to generate a pseudo-random number.
|
| > How does this differ cryptographically from algorithms like
| MWC1616 and xorshift128+ in backend applications?
|
| That question doesn't make any sense. The current timestamp
| would be a seed to initialise the PRNG, which can be MWC or
| xorshift.
|
| > Does it really matter which random number generator you use
| on a webpage?
|
| That is application dependent. If you're coding a roulette
| wheel no, if you're coding an E2E chat yes.
|
| > It's already considered an insecure environment anyway
| (that's why we have server-side validation).
|
| That is also application dependent. The client is considered
| insecure from the server pov because it is entirely under user
| control, so the user can mess with anything. But if it is
| acting entirely on behalf of the user then that can be the
| point and by design.
|
| In the example above, you don't care that a user fucks up their
| own crypto, but you do care that the crypto holds for the
| average user.
|
| Even the qualitative difference between two non-CS PRNG can
| make or break a project due to too small a state space or short
| a cycle.
| sverhagen wrote:
| I don't really disagree with anything you said, but I think
| the roulette wheel and the E2E chat are funny examples, you
| could have a high value roulette game and a casual chat about
| the weather, where the stakes are opposite to your point ;-)
| cratermoon wrote:
| I was thinking this myself. When significant amounts of
| real money are sitting on the spin of the wheel and
| bouncing of the ball, a bad PRNG like the one discussed in
| the article would be disastrous.
| masklinn wrote:
| Yeah I was thinking less casino thingie and more
| https://pickerwheel.com, I guess I used the wrong term
| for it.
| rkangel wrote:
| They're call PRNG because they are _pseudo_ random. If you know
| the starting state, you know what sequence they 're going to
| generate. Putting it another way, if you always start them in
| the same state, they'll always produce the same sequence.
|
| So a PRNG needs "seeding". You need some value to put in at the
| start that is different every time. Using the time on the
| computer results in a different seed on each run, and so a
| different number sequence each time.
|
| If you need random numbers for cryptography (very good quality
| random numbers are important for lots of crypto processes) then
| you need to do more - they need to be completely unpredictable.
| If you just used the time, someone could seed a copy of the RNG
| with the same time, and predict the randomness sequence. So
| what we want is a seed that comes from actual randomness (also
| called "entropy"). That entropy has to come from somewhere -
| ideally some hardware source using some statistically random
| physical effect.
| simonmales wrote:
| Well written, h/t.
| magicalhippo wrote:
| > Putting it another way, if you always start them in the
| same state, they'll always produce the same sequence.
|
| This can be easy to bump into in fairly trivial cases.
|
| For example, initializing by time alone can be problematic if
| you spawn N threads at once which all do their own seeding.
| Then they can all reach the seeding process at the same time,
| relative to the clock used for the seeding.
|
| I had that problem with one of my earlier ray tracers, and so
| had to add add the thread id into the mix to seed the PRNGs.
| markh1967 wrote:
| A demonstration of exactly this problem (only in older
| versions of .Net, newer versions use a different seeding
| method)
|
| https://dotnetfiddle.net/tLGMp6
| mturmon wrote:
| Agreed. I do a lot of Monte Carlo simulations of physical
| systems (radars, scientific models) in which same or close
| seeds will cause trouble.
|
| You do want a deterministic PRNG (for repeatability of the
| simulation). But if you seed with time alone, and spawn 100
| parallel jobs, you will see repeats or near-repeats which
| will bias the Monte Carlo averages resulting from your
| simulation ensemble.
|
| In ancient times, you could xor in the PID and the IP
| address of the host to ensure no seed overlap. Nowadays
| there are other ways to introduce entropy to the seed, e.g.
| with dedicated system calls or /dev/random.
| UncleMeat wrote:
| The key thing with crypto is not the source of the seed, but
| the algorithm. Throwing true randomness into a random number
| generator that isn't mean to provide cryptographic hardness
| won't save you and a cryptographically secure pseudo random
| number generator is often just fine when seeded without true
| randomness.
| toast0 wrote:
| It's both. Cryptographic generators do have better
| properties on their outputs than noncryptographic hashes
| (usually at a cost in cpu time, although the cost is often
| small enough to ignore); but if the seed is guessable, the
| output sequence is guessable too.
|
| Using timestamp in seconds and process id for example would
| be easy enough to guess. There was some good work about a
| decade ago to provide more usable apis to get a quality
| seed from the OS (getentropy, getrandom), so using a self
| built seed is pretty suboptimal unless you have a case
| where you need to repeat the sequence later (recording the
| seed from the OS is also an option)
| UncleMeat wrote:
| It depends on what you mean by guessable. Guessing a few
| bits of the seed with confidence won't help you crack a
| csprng. Yes, people shouldn't be using a timestamp in
| seconds as a seed. But you also don't need to spring for
| hardware randomness in order to get strong protections.
| kbolino wrote:
| The problem with using the current time is that "guessing
| a few bits with confidence" is the same as guessing the
| whole thing because there's only a few bits that need to
| be guessed. You might think a time_t value has 55 and
| growing years worth of values to guess, but in reality,
| if I'm attacking you or something related to you, I have
| probably narrowed it down to days, hours, or even just
| minutes worth of values to guess. Higher-precision timers
| confer some additional entropy but even then it's usually
| not enough -- if I'm intercepting live traffic I have a
| very good idea of the current time, if I'm forging a
| signature from a certificate I know when it was issued,
| if I'm trying to decrypt emails or files I usually have
| attached metadata to narrow my guesses, etc.
|
| The CSPRNG has only made it practically impossible to
| predict future outputs from past outputs _alone_ ;
| however, if I can guess the seed, I can predict _every_
| output past, present, and future. CSPRNGs aren 't magic
| and have to be used properly, and in any security-
| sensitive context, properly means with a _truly random
| seed_. The best CSPRNG in the world cannot create entropy
| out of thin air. It can, however, stretch a good source
| of entropy very far. There are cases when using a CSPRNG
| with a low-quality seed is appropriate, but the minimum
| acceptable entropy in the seed depends on the
| application, not on the RNG.
| UncleMeat wrote:
| I'm not saying to use the current time in seconds. I'm
| saying that the need for "actual randomness" and being
| "completely unpredictable" in the comment I responded to
| is largely overblown. Seeds that aren't drawn from true
| randomness can be totally fine. Seeds that have a handful
| of highly biased bits can be fine.
|
| There are some cases in crypto where a secret that has
| even a single bit biased more than epsilon will break a
| whole scheme. CSPRNGs don't tend to work that way.
| kbolino wrote:
| Ok, yes, there were some algorithms in the past which had
| problems with carrying input biases to their output and
| sometimes even getting totally broken with certain
| seeds/keys. Nowadays, this isn't the case, and the view
| is that such issues are fundamental weaknesses rather
| than mere errata to be worked around.
|
| However, the quality of a modern CSPRNG doesn't save you
| from a low-entropy seed. A couple biased bits in a
| 128-bit seed may not be a serious issue (but why take the
| chance?!), however good entropy estimation is a difficult
| task which is best left to the operating system. Modern
| operating systems will ingest sources of hardware
| randomness and seed their system-level CSPRNGs, which
| should then be used directly by application software (for
| key material) or as seeds to local CSPRNGs (for less
| security-sensitive but more performance-sensitive needs).
| Do not play around with seed entropy just to be clever.
|
| In the absence of a full-fledged operating system, then
| things like high-precision boot timers can be used for
| seeds, but only because there's nothing better available.
| The lack of good randomness is a real problem in
| resource-constrained environments, though usually there
| are easier-to-exploit vulnerabilities that get hit first.
| spacechild1 wrote:
| > I learned in college that most random number generators use
| the current timestamp to generate a pseudo-random number.
|
| People typically _seed_ a PRNG with the current time. The
| actual output sequence is still created with a determinstic
| algorithm. These two things are really orthogonal.
| Retr0id wrote:
| xorshift128+ has exactly 128 bits of internal state. After
| collecting a small number of outputs, it is trivial to
| determine the internal state by constructing and then solving
| an equation (where the variables are GF(2) elements),
| regardless of how the "seed" was initialized. Once you have the
| internal state, you can predict all future outputs with 100%
| certainty.
|
| This only becomes a problem when people assume this isn't
| possible (for example, using it to pick lottery numbers) - this
| is more likely to happen on the server-side than the client-
| side (and v8 runs on both), but it can be security-relevant in
| client-only apps too (consider an insecure "password generator"
| app).
|
| https://en.wikipedia.org/wiki/GF(2)
| Retr0id wrote:
| By the way, the "password generator app" is not a contrived
| hypothetical, it was actually one of my first ever bug-bounty
| payouts.
| markh1967 wrote:
| It's been a while so I can't provide a link but I remember
| reading about someone who got hold of a video blackjack machine
| that used a pseudo random number generator and was able to find
| the seed from only a few hands and then knew exactly which
| cards would be dealt next. He then went on to empty every
| machine he could find in the local casinos.
| lmm wrote:
| > I learned in college that most random number generators use
| the current timestamp to generate a pseudo-random number.
|
| > How does this differ cryptographically from algorithms like
| MWC1616 and xorshift128+ in backend applications? How can a
| random number generator be vulnerable to attacks in real life?
|
| In the early days of online poker some people made a killing by
| figuring out all the possible hands from the PRNGs being used
| and then they could just start a game and look up the hands
| they'd been dealt in their database.
| jansan wrote:
| I wonder why there have not been any updates on v8.dev since July
| 2024. Did Google axe some v8 developer jobs?
| somat wrote:
| ah, the seed, an innocent implementation detail, but many people
| latch on to this and missuse random as a hash function. The one I
| remember was this screwball long term archival system from the
| early 2000's, zipped business archives on cd, the zip files were
| password protected. with the password being a hash of several
| factors about the data(unit, date, etc). A little stupid, but not
| the worst thing I have ever seen. The bad part was the hashing
| algorithm used, it was perls rand(). When I saw that I was
| vaguely horrified and a few test's confirmed my fears, the perl
| rand function would vary across operating systems and even
| different version of perl would change it. I think they ended up
| having to keep an explicit database of all the passwords just to
| have a fighting chance at opening those files later. not that
| they ever would. no one ever looks at long term records once they
| are stored.
|
| Anyway, I like how the openbsd folk fixed the old C rand family
| of functions. they made their seed functions do nothing and tied
| the generators to a strong kernel random source, that is, they
| made rand actually random. If your application actually depends
| on rand as a hash function they provided the old behavior under
| srand_deterministic(3)
|
| "Standards insist that this interface return deterministic
| results. Unsafe usage is very common, so OpenBSD changed the
| subsystem to return non-deterministic results by default."
|
| makes me laugh every time.
|
| http://man.openbsd.org/rand
| lionkor wrote:
| That's an interesting story, thanks for sharing.
|
| However, it is the reason that (what feels like) every single C
| function has a footnote, along the lines of "*except on FordBAT
| OS, where mkdir doesn't create a directory, all floats are inf,
| and negatives are positive -- because it seemed convenient"
| kevin_thibedeau wrote:
| > they made rand actually random
|
| That is a phenomenally stupid thing to do. There is legitimate
| need for reproducible pseudo-random sequences derived from a
| known random seed. If you break seeding that can't be done.
| This is how fuzz testing with generated inputs works.
| twic wrote:
| The spec [1] only requires that the sequence of pseudo-random
| numbers is repeated for a given seed within a single process
| ("subsequent" and "is then"). That means rand as specified is
| useless for reproducible sequences in fuzzing and so on. So,
| programs which do that already need to supply their own
| random number generators, and are not affected by this
| change.
|
| Whereas lots of programs use rand as a source of general-
| purpose random numbers, but get the seeding wrong, and so
| suffer from various problems. This change fixes those
| programs.
|
| [1] https://pubs.opengroup.org/onlinepubs/009696699/functions
| /ra...
| aidenn0 wrote:
| That's an interesting way to read the specification, seems
| contrary to the intent and differs from how historic unix
| systems have implemented it. The author of the man page
| _also_ disagrees with you on it being allowed by the
| standard ( "If the standardized behavior is required
| srand_deterministic() can be substituted for srand()...").
|
| Fucking things up for people who understand how PRNGs work
| just to fix things for people who don't seems backwards;
| things like this is why configure scripts take over a
| minute to run. I might be okay with the non-determinism in
| rand() if srand isn't ever called, but intentionally
| ignoring the stated intent of the program just pisses me
| off.
| kbolino wrote:
| > non-determinism in rand() if srand isn't ever called
|
| This is the path Go took for its math/rand library
| eventually: if you don't seed the RNG, it's a CSPRNG, but
| if you do seed it, it's deterministic.
|
| However, there is lots of "advice" out there to seed your
| RNG with "random" values like the current time to make it
| "more secure" (and to be fair, in some cases, you may get
| sufficient entropy for the purpose at hand by doing this,
| but in most cases, you won't get enough and you'll spend
| it very fast). So a call to srand _may_ indicate that you
| know what you 're doing and want determinism and
| understand the consequences, but it doesn't necessarily
| mean that.
| cpeterso wrote:
| > seed your RNG with "random" values like the current
| time
|
| Good point. srand(time(NULL)) is a common, yet
| nondeterministic, seed. The caller clearly doesn't expect
| rand() to generate a particular sequence of numbers, so
| srand() could check whether the given seed looks like a
| time_t close to the current time() and, if it does, then
| use a proper CSPRNG instead.
| leni536 wrote:
| That's a horrifying suggestion.
| kbolino wrote:
| Since any good solution would start with deleting rand
| and srand from the C standard library entirely, but
| that's never going to happen, we only have not-good
| solutions to consider.
| __s wrote:
| Amusingly in go 1.24 they're turning srand into a nop:
| https://github.com/golang/go/issues/67273
| crdrost wrote:
| That is a legitimate need, but it should not be the default.
|
| Another example of when you need it, is games. I want to
| store in the game state, that on Day 32 of being in this
| cave, there is randomly a cache of diamonds if you mine the
| east wall. If I generate this random number dynamically, then
| I permit save-scumming behaviors which may distract from the
| artistic points of my game. So I basically want a random seed
| and a hash function, hashing (seed, day, activity, location,
| attempt_number) to see if something is successful.
| kbolino wrote:
| Yes, there is a legitimate need, and when you know you need
| it, you have already demonstrated you know what you are
| doing, and therefore can find the proper tool, even if it's
| not the default.
|
| Whereas, when you don't know what you're doing, the default
| should not be a footgun.
| kevin_thibedeau wrote:
| C has a standard library with known guarantees. Pulling the
| rug on those guarantees is irresponsible.
|
| The appropriate solution is to not break anything and use
| tooling that flags use of banned symbols that can have
| negative safety or security implications.
| kbolino wrote:
| The problem is not that OpenBSD doesn't follow the
| standard, it's that the standard is wrong. The default
| random number facility should be cryptographically
| secure. Most developers do not know the difference;
| giving them a deterministic, somewhat more performant,
| but completely insecure RNG by default expresses the
| fallacious assumption that they do. This is not the 1980s
| anymore, virtually every computer is connected to the
| Internet, there are hundreds of millions of software
| developers across the globe across all skill levels, and
| now we have them using LLMs to contend with as well, such
| naivete is no longer sustainable.
| mystified5016 wrote:
| Having your random number generator be deterministic by
| default is extremely bad. Using a deterministic seed should
| be the exceptional case.
|
| In those cases, they provide deterministic operation under a
| different set of functions so nobody does anything as stupid
| as using deterministic RNG as encryption
| Someone wrote:
| But if you compile some third-party code that doesn't know
| of that API change, and then use it, that can lead to
| disaster. For an example, see the GP post at
| https://news.ycombinator.com/item?id=42971287.
|
| I think it would have been better to remove _rand_ and
| _srand_ , and provide two replacement functions with
| different names, or require all users to pick one using a
| _#define_.
| somat wrote:
| Yes, and that function goes by several names, I call it the
| hash function, a deterministic operation that returns
| unordered results. The non-deterministic variant of this I
| call random(). if you want deterministic results, you should
| use the deterministic function.
| duskwuff wrote:
| > There is legitimate need for reproducible pseudo-random
| sequences derived from a known random seed.
|
| Correct, but rand() / srand() aren't an effective way of
| providing for that need. The state of the RNG is process-
| global; it rapidly becomes nondeterministic in multithreaded
| applications, let alone if a library you're using calls
| rand() internally. And, as mentioned upthread, the algorithm
| is implementation-defined, and isn't guaranteed to remain the
| same over time.
| wruza wrote:
| For the curious, xorshift128+: uint64_t a = s[0];
| uint64_t b = s[1]; s[0] = b; a ^= a << 23;
| a ^= a >> 18; a ^= b; a ^= b >> 5; s[1] = a;
| return a + b;
|
| https://stackoverflow.com/a/34432126
| Retr0id wrote:
| Fun fact, the state update function can be modelled as the
| multiplication of the state vector by a constant matrix (where
| the vector/matrix elements are all in GF(2)). By raising that
| matrix to a power n, you can use the resultant matrix to
| compute n state updates at once, allowing you to "skip ahead"
| arbitrarily into the output stream.
|
| Hypothetically, you could use this to vectorize/parallelize
| computation of xorshift128+ output sequences in large batches,
| but I'm not sure anyone's ever bothered to do this because the
| naive sequential method is so cheap.
| shiftingleft wrote:
| The easiest way to parallelize this RNG is to just run it in
| parallel on multiple states.
| somewhereoutth wrote:
| If anyone wants a seedable, and therefore deterministic PRNG, use
| the seedrandom package https://www.npmjs.com/package/seedrandom
| // Global PRNG: set Math.random. seedrandom('hello.', {
| global: true }); console.log(Math.random()); //
| Always 0.9282578795792454
|
| I found this useful when using worker threads to 'render' a
| construction by slices that included some randomness (that should
| be the same for each thread)
| svachalek wrote:
| Replacing a system function is a quick and easy hammer but not
| great for maintenance. It's not clear that calls to
| Math.random() are now actually going to an npm, and if someone
| deletes that seedrandom line it's not clear that calls to
| Math.random() are now _not_ actually going to an npm.
|
| For new/clean code it's better to just import a seeded random
| function for clarity.
| kittikitti wrote:
| Thank you so much for this, by coincidence I was looking for good
| sources about Pseudo Random Number Generators and how we program
| them. This does the trick and explains the levels of determinism
| and the most popular PRNG algorithms.
| GrantMoyer wrote:
| Xorshift is really cool because of how simple it is to comprehend
| and implement despite how well it works as a PRNG. The initial
| paper describing it, "Xorshift RNGs"[1], is surprisingly short
| and approachable, and I encourage anyone with any interest to
| read through it.
|
| [1]: https://www.jstatsoft.org/article/download/v008i14/916
| pavel_lishin wrote:
| It doesn't seem to work well for smaller sizes when shifting
| left by 1. I'm sitting in a waiting room, playing with this on
| paper with four-digit binary numbers, and so far it seems to
| rapidly fall into a loop of 1,3,5,15,1...
|
| edit: they all fall into their own loops. I forget the term for
| it, but the pattern is, unless I've made an arithmetic mistake
| (likely!):
|
| 1,3,5,15,1...
|
| 2,6,10,14,2...
|
| 4,12,4...
|
| 7,9,11,(1,3,5,15,1...)
|
| 8,8...
|
| 14,7,9,11,(1,3,5,15,1...)
| codesnik wrote:
| One mistake that bitten me a couple of times is not to reseed
| after fork(). AFAIR Perl calls srand automatically on fork, and
| I've been surprised that ruby at circa version 1.8 - didn't,
| which gave me quite some interesting behavior on production.
|
| I'm sure some other runtimes don't do it, too.
| eternauta3k wrote:
| What applications care about this improvement, considering it's
| not cryptographically secure?
| GrantMoyer wrote:
| I've hit issues with bad quality PRNGs when using them for
| Monte Carlo path tracing. With a non-uniform PRNG, the
| simulation can take a lot longer to converge to a clear image,
| because some ray paths can be severely under or over
| represented.
| paulpauper wrote:
| the solution is to the use the RNG to build a key , not create
| the key with the bad RNG
| pseudosavant wrote:
| Funny to see this coming up again after all these years. I was
| the person who reported this issue to the Chromium team, 3 years
| before that blog posts. They marked it as won't fix, multiple
| times (other people reported it too), before they fixed it.
| Safari, Firefox, and IE were all already using more robust PRNGs
| for Math.random() that did not exhibit this issue.
|
| https://stackoverflow.com/questions/9550796/why-is-google-ch...
| https://issues.chromium.org/issues/40404440
|
| I came across it because of some tests I had for a statistics
| library I was working on. There was a test that created an array
| with 100k random values that shouldn't have had any collisions,
| but I consistently got multiple collisions, only in Chrome.
| magicalist wrote:
| Pretty sure it was [1] that finally got them moving (old hacker
| news discussion here[2]). Not to take away from your bug
| report, but there were a bunch :) The main issues were that the
| spec allows engines to pick their own implementation (including
| only having 2^32 possible values) and there were benchmarks
| like sunspider where overfitting encouraged the implementation
| to be as fast as possible. That was a lot less of an excuse for
| the RNG they used in 2012-2015 compared to when it was added in
| 2007 or 2008, but by then there was a decent argument that
| developers should go to crypto.getRandomValues() if they wanted
| actual random values, which probably stalled action longer than
| it should have.
|
| > _Safari, Firefox, and IE were all already using more robust
| PRNGs for Math.random_
|
| This wasn't true at the time. I actually don't remember what
| Safari was doing in 2012 so I won't say that one for sure, but
| Firefox and IE were both using garbage RNGs as well, they were
| probably just generating across the full (or at least more of
| the) (0, 1] double range so didn't produce the collisions you
| saw in your testing.
|
| [1] https://medium.com/@betable/tifu-by-using-math-
| random-f1c308...
|
| [2] https://news.ycombinator.com/item?id=10598065
| brunoborges wrote:
| I am curious what other languages (and runtimes) have been using
| so far. Anyone knows?
___________________________________________________________________
(page generated 2025-02-07 23:01 UTC)