Math.random errors after 2^31 - 1 but Random object does not

math.random() will return an error math.random(1,2147483648):1: bad argument #2 to 'random' (interval is empty) when given any number greater than 2^31 - 1.

This only happens when the first argument to math.random is less than 2^31, or isn’t provided.
ie.
math.random(2147483648, 2147483648) will not error
math.random(2147483647, 2147483648) will error
math.random(2147483648) will error

This is not consistent with the Random object, which handles intervals of any size (albeit the returned number exhibits overflow symptoms).

This function either should not error (as is consistent with Random), or should throw an error that makes sense to avoid confusing developers, and Random should be updated with the same behavior.

It looks like Random accepts an interval defined in any order, while math.random requires the first argument to be less than the second. This is why only math.random throws.

6 Likes

This is happening because you’re getting an integer overflow, causing it to think the second argument is less than the first. When the second argument is less than the first, you get the weird “interval is empty” error (e.g. math.random(2, 1) will throw the same error). I don’t think this is a bug, but rather a side-effect of the random function being limited to 32-bit numbers.

2 Likes

That is the bug. It should not be limited to 32-bit numbers if Random objects are not. This function throws an error about it but Random just eats it. The behavior of this should be consistent.

1 Like

I saw this a couple of minutes ago as a question,
So I tried a number as big as that in an online compiler with math.random, and it did work. The compiler used lua 5.3 and roblox uses 5.1.4. So yeah

This is because the 5.3 numeric system is much different than 5.1’s. The integer subtype in 5.3 is a long long which limits it at roughly 2^63 as opposed to 2^31 numbers in 5.1’s double->int casting.

math.random’s 2-argument form has always converted the arguments to signed 32-bit ints, and math.random is being kept alive for legacy code, with as little change to it as possible (except where actual bug fixes were needed). All new code should use Random NextInteger and NextNumber. Random is intended to be an improvement over math.random, so having them behave consistently was never desired or a requirement.

1 Like

The problem with this is that, in large scale multiple-per-second calculations, Random.new() is slower overtime.

Random.new() is the constructor for the generator itself, there is no use case where you would call it in a loop. Most commonly, you only need to call it once within a script that uses it. You assign the reference it returns to a variable, and call NextInteger and NextNumber on it to get the random numbers. These will be faster than math.random(), because math.random now redirects to NextInteger and NextNumber internally, but with some conditional overhead and conversion of the arguments. Calling the new Random API functions directly removes a level of indirection.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.