Whats the lowest number math.random() can produce

Like the lowest decimal, that isnt 0

1 Like

This is just not true. By default, just like usual in any other programming languages, when you don’t provide any arguments, it returns a decimal between one and zero. zero included.

1 Like

Actually, it does. You just do:

local Decimal = math.random(0.0, 120.0)

my bad guys, I thought otherwise

1 Like

No, This still isn’t true, you would need to use Random.new() for this:

Random.new():NextNumber(.1, .5) -- 0.15655854882102088 (what I got)

math.random only returns Integers

Please read my previous post. The expression math.random() will return decimals. or floats. or doubles. whatever you want to call it.

1 Like

Mate, pls try out the code I provided

I did, it returns integers not decimals

Putting “.0” really doesn’t make the interpreter interpret the number differently. This isn’t C# or any other statically typed language.

3 Likes

From what I see with math.random(), it can only handle numbers from the Positives, all the way up to around 1e10

However with the Negatives, it appears to stop at around: -2147483648 from what playing with math.random returned

Which I’m not sure as the Max Integer limit is at around 9.2 quintillion., while Floats return higher.

If you want larger numbers, try Random.new():NextNumber Random.new():NextInteger seems to not cause the Interval is empty error as it stops at around 9.2 quintillion as if it goes over, it becomes a negative (I could be wrong as I’m not aware of new limits)

2 Likes

That’s because math.random negatives utilizes int32 instead of int64, it seems like that the number becomes negative is just a fail-safe catch to prevent an error with Random.new()

1 Like

I can’t for the life of me figure out why positive numbers for math.random() go up to 1e10, do you by any chance know why?

Yeah, you basically said why, int32 can only handle numbers at around 2 trillion, I made sure to test and:

print(math.random(2147483646,2147483647))  -  Studio
 23:09:34.960  2147483646  -  Edit
print(math.random(2147483646,2147483647))  -  Studio
 23:10:49.978  2147483647  -  Edit
print(math.random(2147483647,2147483648))  -  Studio
 23:11:13.853  print(math.random(2147483647,2147483648)):1: invalid argument #2 to 'random' (interval is empty)  -  Edit

It appears that is the exact limit
1e10 is basically 10 trillion while 1e9 is 1 trillion, so that makes sense

(I think its billion but Im bad at counting, sorry)

1 Like

But that’s 2.147 billion, not trillion. So it wouldn’t make sense why it goes to 10 billion

1 Like

Billion = 9 zeros
Trillion = 12 zeros

For some reason i always confuse billion with trillion.

1 Like

It you want really, really small decimals, just divide the integer range.
This would give you 0.001 to 1 for example

math.random(1,1000) / 1000

Or 0.000001 to 1, etc.

math.random(1,1000000) / 1000000

[edit] Hit wrong reply button

Okay, no.

print(math.random()) --> 0.245837...

Second of all, there isn’t really an answer to this. It’s a very low unknown number.

It’s possible that math.random() uses 64-bit floats, but I believe the old library functions use 32-bit floats. If that’s indeed the case, the smallest number greater than zero is 1.40129846432e-45, or a 1 preceded by 44 zeroes.


How are you testing that?
image


It’s actually faster to multiply by the integer range.

math.random() * 1000

For what it’s worth, the actual limits of signed 32-bit integers are -2,147,483,648 and 2,147,483,647. Only the right-most digit is different. These numbers are -2^31 and 2^31-1. For unsigned (positive only) 32-bit integers, the range is from 0 to 2^32 (32 being the number of bits) or about 4 billion. By going from 2^32 to 2^31 with signed numbers, we halve the number which is representative of splitting half of the number above zero and half of it below zero.
Also, 2^31-1 is a Mersenne prime number.

I’m astounded by the misinformed answers here.
Some answers here implicitly misinterpret the topic being about math.random with one or two arguments (the version that returns the abstract integer data type) rather than math.random without any arguments, as this is implied by the word “decimal” at the original post and math.random without argument returns an abstract float whereas math.random with 1 or 2 arguments returns an abstract integer.


Looking at the source code, math.random with no argument always uses (not it is possible that but that it does use) C’s double in Luau; it does not use the C’s float.
luau/VM at master · Roblox/luau · GitHub

    case 0:
    { // no arguments
        // Using ldexp instead of division for speed & clarity.
        // See http://mumble.net/~campbell/tmp/random_real.c for details on generating doubles from integer ranges.
        uint32_t rl = pcg32_random(&g->rngstate);
        uint32_t rh = pcg32_random(&g->rngstate);
        double rd = ldexp(double(rl | (uint64_t(rh) << 32)), -64);
        lua_pushnumber(L, rd); // number between 0 and 1
        break;
    }

Is there really no answer?

For OP - I believe this section will also be relevant for you, as this section (hopefully) answers the original post.

Look at the Luau source code - luau/lmathlib.cpp at master · Roblox/luau · GitHub

    case 0:
    { // no arguments
        // Using ldexp instead of division for speed & clarity.
        // See http://mumble.net/~campbell/tmp/random_real.c for details on generating doubles from integer ranges.
        uint32_t rl = pcg32_random(&g->rngstate);
        uint32_t rh = pcg32_random(&g->rngstate);
        double rd = ldexp(double(rl | (uint64_t(rh) << 32)), -64);
        lua_pushnumber(L, rd); // number between 0 and 1
        break;
    }

Observing this, you can see that rd is the value returned for math.random with no arguments and the value of rd is defined as ldexp(double(rl | (uint64_t(rh) << 32)), -64) - ldexp(x, exp) is abstractly defined as x * 2**exp. You can also see that rl and rh are randomly generated in the range of unsigned 32-bit integers; it could any value from 0 to 2**32-1 but given that it’s randomly generated, we don’t know what the exact value is.

To find the smallest value, find the smallest value of the x as the exp is constant, as the abstract definition of ldexp implies that as the x approaches to 0, the return value of ldexp decreases - but because the x argument in this case is double(rl | (uint64_t(rh) << 32), the smallest value would be rl = 0, rh = 0 which is ldexp(0.0, -64) which is 0 * 2**-64 which is 0.0, but the original post states that the smallest value that isn’t zero, so try rl = 1, rh = 0 which is ldexp(1.0, -64) which is 1 * 2**-64 which is 2**-64.
This concludes that the smallest value math.random without arguments can theoretically return is 2**-64 in Luau albeit the internal rl and rh have to be 0 and 1 respectively which is a 1 in 264 chance of that happening.


math.random with two arguemnts can handle zero and negative numbers as long as the interval isn’t empty (the upper bound is greater or bigger than the lower bound) - not sure where did you get the statement that it can only handle positive numbers from.

If you provide a Luau native "number" that is out of the range (of the argument of these functions that internally cast the value to an internal fixed-width integer data type) into both 2-argument version of math.random(x, y) or Random.new(...):NextNumber(x, y) it is not always going to “become a negative value” (so that the interval will be empty) as it is an undefined behaviour as internally math.random uses luaL_checkinteger to convert from Luau "number" (which is a double) to a fixed-width integer, and Random.new(...):NextNumber perhaps uses something similar.

5 Likes

yo so like whats the lowest number cuz i aint readin allat
ty for ur help tho