Sure… how many finite values between 0 and 1 exist in a float?
Well that boils down to how floats store values:

There is a sign, an exponent, and the ‘mantissa’/fraction. Note that the mantissa is 23 bits, but implicitly stores 24 bits because there is an implied 1 (all non-zero binary values have a leading 1 so it doesn’t actually store that 1 and just assumes it is there).
Note that the exponent value is actually the number stored there - 127. So this means that 0.5 is just:
01111110 00000000 00000000 00000000
That is no sign, 126 in the exponent (equals -1), and 0 in the mantissa. Which equates out to 1 * 2^-1 in scientific form, or 1/2.
All fractional values will be every possible value representable in the mantissa multiplied by the possible number of exponents that would result with any of those values shifted with all of its digits to the right of the radix. Honestly… I don’t know a simple proof for all of the exponents off the top of my head… but really it doesn’t matter. Because what we do know is this… the digits in the mantissa, including 0, is even. And an even * any number is always even. So we know whatever the number of values that can be represented is… it’s an even number.
BUT… this does not include 1! 1 is outside of this set.
So the number of values from 0->0.99999… that can be stored in a float is even. And if we include 1 then it’s odd (because an even + 1 = odd).
If we split a set in half whose length is even, then we result in 2 sets that are of the same length.
{0,1,2,3,4,5,6,7,8,9}
{0,1,2,3,4} {5,6,7,8,9}
But a set of length odd split in half results in 2 uneven sets.
{0,1,2,3,4,5,6,7,8,9,10}
{0,1,2,3,4} {5,6,7,8,9,10}
Now lets just assume that Random.value is a perfectly uniform RNG (we can’t actually guarantee that unless we knew the exact algorithm used. But lets just assume for sake of discussion). Meaning that it returns every possible value from 0 to 1.
If it excludes 1, then we result in an even count of values, meaning that we need to put the 0.5 into the top set. We can do that by saying >= 0.5 or < 0.5.
If it includes 1, then we result in an odd count of values, meaning that we can’t split the set evenly. Putting 0.5 in the upper set skews us towards the upper, and putting it in the lower set skews us to the lower.
This is part of why most RNG algorithms, say like System.Random, actually return in ranges of 0->1, 1 eclusive (it’s not the only reason, and actually is one of the lesser reasons as I’ll get into later):
https://learn.microsoft.com/en-us/dotnet/api/system.random.nextdouble?view=net-8.0
BUT, Unity’s Random.value actually returns 1 inclusive:
https://docs.unity3d.com/ScriptReference/Random-value.html
This means we can’t guarantee perfect uniformity.
But what is exclusive of its top range? Random.Range(int, int)!
So if you want perfect uniformity, you should tend towards Random.Range… even though Eric5h5 says it’s slightly slower in that post you linked. Because while its technically slower… it’s negligibly slower.
BUT… speaking of negligible.
There’s billions and billions and trillions of values between 0 and 1. Also, we’re assuming that Unity’s algorithm is perfectly uniform… which it likely isn’t! So 2 things could happen here.
-
It’s not perfectly uniform, it results in an odd number of possibilities, and the inclusion of 1 as an upper makes it even. In which case it’s an even split… but we don’t know where that exclusionary midpoint is (since the non-uniform values are noise across the set) meaning this is all for not. Resulting in a noisy/random skew that is likely imperceptible in real-life scenarios.
-
It is perfectly uniform and that skew towards the top is 1/gajillion… which… really? Does your game need to care about that 1/gajillion skew?
So really at the end… it doesn’t matter! (this is why really most RNG algos excluding 1 has less to do with this unformity, it actually just has to do with usefulness in arithmetic)
But… if you wanted to know the math. There you go.