Ah, so we don't care about mathematical rigor, yet we're discussing a proof of the pure mathematical behavior?
> It’s quite reasonable to implicitly treat this discussion as a question within the domain of true mathematical reals,
So we do care about mathematical rigor?
> It’s still false that “rand(rand()) == rand() * rand() relies on uniform distributions”.
Consider a distribution A(r) uniform on [0,r) except it never returns 1/4. This is a perfectly valid distribution, extremely close to being the same (in the mathematical sense) as the uniform distribution itself.
A(A(1)) will never be 1/4. A(1) * A(1) may be 1/4. Thus the claim needing uniform (or a proof for whatever distribution you want) requires careful checking. And if you don't like this distribution, you can fiddle with ever larger sets (in cardinality, then lebesgue measure zero) where you tweak things, and you'll soon discover that without uniform, you cannot make the simplification. And I demonstrated that the actual PRNGs are not uniform, so much care is needed to analyze. (They're not even continuous domain or range)
Yes, if you define the rng circularly, then you can make the assumption, but then you cannot make the claim of 1/2 per term, since they are not uniform. If you define the rng more carefully, then they often don't commute (maybe never?).
For example, defining the rng in another reasonable (yet still naive) fashion to keep more bits:
float rnd(float max)
i = int_rand(N) // 0 to N-1, try weird N like N = 12345678
f = i*max
return f/N
this does not satisfy rnd(rnd()) == rnd()*rnd() in general, as you can check easily in code.Thus, to make the claim you can swap them requires for the mathematical part true uniformity (my claim way up above) and for the algorithm sense it requires knowing details about the underlying algorithm. Simply having a rnd(max) blackbox algorithm is not enough.