The distribution of mt_rand() return values is biased towards even numbers on 64-bit builds of PHP when max is beyond 2^32. This is because if max is greater than the value returned by mt_getrandmax(), the output of the random number generator must be scaled up.
edit: this post went from 5 points to 1, which I don't care about(in ~500 days I posted less than 10 times and I have ~35 points), but who downvotes documentation, seriously? -_-
<Friday afternoon trolling is just too easy this week />
I assume things are much better now, but I remember a time when things like INSERT <table> (<date_field>) VALUES ('2015-02-30') would not have raised any sort of error, amongst other terrible things that people would defend having to implement explicit checks for in other layers of your application.
systemd is by no means alone; in the last month I've discovered that `yum` deliberately breaks its output when you try and pipe it to something else (I mean really, ffs, really?). The justification for this isn't even internally consistent which really winds me up too...
Whilst I pick on a couple, there's been innumerable packages, languages and platforms over the years that have had their share of what could politely be called idiosyncrasies. I highly recommend The Unix Haters Handbook  for plenty of historic examples -it's a lovely read -oh, and for years one of the *nix bullet points was always "all the power in the world and not a safety in sight" 
 The Unix Haters Handbook: https://en.wikipedia.org/wiki/The_Unix-Haters_Handbook || http://www.csf.ac.at/fileadmin/user_upload/BioComp/training/...
 The Hole Hawg: https://web.archive.org/web/20150214132948/http://www.team.n...
Gnome depends on logind, which is sensible. Yes, logind is part of a suite of system management tools which also includes tools to manage the boot process.
Your complaint would apply equally to your window manager being intrinsically linked to your serial port (via the Linux kernel).
Until a couple of years ago, my linux box was nearly entirely modular letting me install any combination of boot-loader, kernel, init system userland tools and/or desktop. How is this better?
The best thing to do is to not use mt_rand().
Because this is not a simple, stupid linear congruential generator. mt_rand(), is, as I understand it, based on Mersenne Twister, a well-regarded generator which has a period of 2^19937. And if PHP had done this right, mt_rand() would be seedable with an array of some 624 integers.
Mersenne Twister has an alternative "classic" seeding algorithm, drawn from Knuth, to be compatible with old-style generators. This algorithm takes a 32-bit seed. Apparently that's all that PHP is supplying.
It's dead simple to do random(n) uniformly. When I heard that some language implemented a function called mt_rand() which was hilariously broken in this respect, the first thing that came to my mind was "that's gotta be PHP". And it was.
Returning garbage when one of your parameters is beyond a certain limit is "crazy behavior." Either support it properly, or don't support it at all.
I don't think a language like PHP, or indeed anything written in it, should have undefined behavior but I'm not the author of the library.
If you expect input parameters in some range and you get values out of that range, then you blow up. You don't silently truncate anything and you certainly don't reduce the entropy of your random number generator by nearly 50%.
And yes, in the eleventy billion cases where PHP should yell at you that it's doing something totally different than what you wanted, it instead just goes about its day silently.
MySQL was once actually superior open-source database, being more performant and simpler to setup and use than PostgreSQL. And then, once again, it just got popular.
I don't think being faulty helped these technologies, although it sometimes is the case.
It's not. White it does have several surprising behaviors, "almost everything" is just an example of uniformed BS people say when it comes to PHP.
EDIT: because of HN's annoying "you are posting too fast" limit I cannot reply to the comment below.
The arguments against Exceptions began in the comments on the relevant pull request: https://github.com/php/php-src/pull/1397
At what point do we stop blaming the developers for not knowing how to
use our badly designed features, and accept responsibility for exposing
an API that is hostile towards simple, efficient, and correct implementations?
php > echo PHP_INT_MAX;
It doesn't surprise me that people might not notice the existence of that second warning. I believe that most developers wouldn't scroll down to read the changelog and the example if they think they understood what the function does from its description.
echo "<?php echo mt_rand(-mt_getrandmax(), mt_getrandmax());" | php
It may never have been designed to. If it was written before 64-bit machines were commonplace, mt_getrandmax() would always be the same as PHP_INT_MAX.
Oh well, ofc. because this is PHP which goes by the principle of most surprise.
How does that answer anything?
The problem is way worse than you think. Check out what this looks like when printed in hexadecimal: http://3v4l.org/XVTgS
Basically, what is going on is that PHP_INT_MAX is 2^63 - 1. mt_getrandmax() is 2^31 - 1. The way mt_rand() makes a random number when the limit is too large is that it makes a random number in the range [0,2^(31)), then it scales it to be a number in the range [0,MAX-MIN), and finally adds MIN.
So in your case, it scales everything by 2^32 and adds 1. Which is why the numbers are* extremely non-random. [See my other comment in this thread for a more detailed explanation and some more test scripts that prove this is what is happening.](https://www.reddit.com/r/lolphp/comments/3eaw98/mt_rand1_php...
My employer is leading the effort to expose a compatible interface in PHP 5 applications so developers can add one line to their composer.json file and start writing code for PHP 7. It's MIT licensed and should nearing its 1.0.0 release soon.
Everybody should know by now that the mersenne twister is not only bad, but also slow.
Everybody should know by now that the first bits are good, and the last bits horrible. That's why you should not use modulo %, but rshift or better use Melissa E. O'Neill's PCG, which uses the first good bits to improve the latter worse bits.
Most RNGs are at bottom stream ciphers. The stream cipher problem of stretching a small key into a very large keystream is fundamental to cryptography, and RNGs are an instance of that problem in the most favorable setting: no message boundaries and no coordinated state.
You don't in practice worry about AES-CTR "running out of key", and so you shouldn't worry about urandom "running out of entropy".
It's understandable why so many people believe this: the Linux urandom man page invents a whole parallel universe in which this is not only a live issue, but one with applications to specific kinds of cryptography! Until we find the appropriate incantations to shut down that particular portal to the world of the Elder Things, it's best just not to look at it.
Stretching of the key means (at least in theory) that you could break the random function and predict the random series or your position in it.
I guess your point of not worrying about ordinary key encryption should be applicable in an RNG context too and be similarly safe, though.
mt_rand() performs worse than CSPRNGs, funny enough
Using a strong PRF we can take a 128-bit seed and turn it into an endless stream of random numbers. If /dev/urandom drains entropy, that's a bug that your OS should fix.
> Everybody should know by now that the first bits are good, and the last bits horrible. That's why you should not use modulo %, but rshift or better use Melissa E. O'Neill's PCG, which uses the first good bits to improve the latter worse bits. http://www.pcg-random.org/
Yeah, there is no pgc_random() function in PHP though.
Because the Mersenne twister is outdated technology, which
is bad and slow. Use pcg instead.
> If /dev/urandom drains entropy, that's a bug that your OS should fix.
Defying logic? Without a HW source for noise that's impossible. Even if people are arguing being practical to drop security, you should not be convinced.
I didn't see tests which would confirm this theory.
> Yeah, there is no pgc_random() function in PHP though
Writing that binding would cost a php-c dev 20 minutes. But they should not.
The problem is the bike shedding to replace that in the stdlib for rand(). Better, faster? But...
Most PHP devs are not C devs.
$ man urandom
This script was stopped while abusing our resources"
PHP may not do a very good job at ensuring an even distribution throughout the space of possible integers, but for PRNGs in general (especially the quick & dirty ones), the worst place to grab bits from is the least-significant bits.
(my source is that I hung out with a copy of Numerical Recipes in college; Numerical Recipes has a nice chapter for learning about PRNGs, along with example code for a number of implementations)
But yes, in general the rand-modulo pair is an anti-pattern.
In the specific case of mt_rand, MIN_RAND is 0 by default, then the modulus needs to divide (MAX_RAND + 1).
In the general case, there's no rule in any uniform continuous implementation of rand such as (modulus + 1) needs to divide a specific number.
You're using a bucket size which is a power of 2. A random byte fits on the interval of [0, 255] which is evenly distributed modulo 256, which if you reduce mod 2^N for 1 < N < 8 will still produce a uniform distribution.
If you copied my JS code into your console and changed the 54 to 64 the bias evaporates. Hooray :D
However, for arbitrary ranges, you should use an unbiased selection strategy to ensure a uniform distribution.
http://3v4l.org/EgfPR - notice 0 is significantly more common than the other values when reduced mod 17
http://3v4l.org/LXmKq - same with mod 15
This avoids a lot of frustration. Imagine if this was called someObj.sqrt(x). People could jump to the conclusion that this takes the square root of a value, when in reality it only does so on weekdays. On weekends it returns the CPU temperature.
When I need to write a function with lots of complex interactions, I mash the keyboard rather than try to come up with a name that's misleadingly simple. That way you have to read the documentation.
If there is no smiley in the function name it won't pass QA here.
This illustrates some problems with the PHP way of doing things. For some reason the PHP internals community prefers to have this function continue to spit out garbage when given invalid inputs instead of throwing an error, especially if spitting out garbage is what was done in the past. The answer is always, "Don't do that. RTFM." but most developers don't read the documentation for each and every function that they use, but rather rely on the name of and common sense until there's a error. If there's no error, the documentation never gets read.
I really wish there was more support behind the idea of creating a new standard library and gradually deprecating the old one, it's been tried but never gets any traction.
Meanwhile frameworks and libraries continue to add their own (often very good) helper libraries to smooth the edges.
For ever number k there exists -k which has the same parity as k (that is, if k is even, -k is even as well)
For every k there is (k + 1) with opposite parity (same thing with -k and -(k + 1)
Now, if we count the numbers, from 1 to infinite, the number of even and odd numbers is the same
from 1 to -infinite the number of even and odd numbers is the same as well
And you get an extra zero, an even number
Curious what is possible in Integer numbers
> That's what happens when you try to reason with infinity ;)
Ah yes! Fascinating subject
The "infinity" referenced here, aleph-null, is provably both the cardinality of the set of even integers, and the set of odd integers. (And also the set of integers, and any other countably infinite set.)
So, unintuitive as it might be when thinking about finite subsets of the integers, there are not only as many positive integers as negative integers, but as many of either as there are integers.
(There are, however, bigger infinite sets, there are, for instance, more reals than integers.)
There are as many prime numbers as there are integers.
There are as many fractions between 10 and 11 as there are integers.
There are more real numbers between 41.00001 and 41.0002 than there are integers from -infinity to infinity. Even though both are "infinite."
From http://windows.php.net/: "The x64 builds of PHP for Windows should be considered experimental, and do not yet provide 64-bit integer or large file support." PHP's principle of most surprise in action.
this has never been observed.
If so, we are looking very hard.
But then, 10^-37 is a very low number. I wouldn't be surprised if that means that all neutrino detectors could catch one, but failed to do so up to now.