In some cases, in Lua 5.1 (Lua 5.0 and earlier have no hexadecimal literals); when you enter a large hexadecimal literal, it caps at 263 (or 232 depending on the platform). If you type in numbers like 0x10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
, it’ll return 1.844674407371e+19
or 4294967295
(assuming IEEE 754 double is used as a number) despite the literal being equivalent to 21024 and only IEEE 754 double precision as the only numberic data type in Luau (IEEE 754 infinity)
In Roblox’s case, it returns 1.844674407371e+19
(18446744073709551615 technically but because value specified by IEEE 754 double precision floating point format loses precision and rounds integers after 253 via half even so it’ll print 18446744073709551616)
Though I don’t know anything about what causes this bug, I suspect the bug is caused by C’s compiler; I know that C89 doesn’t support hexadecimal floats while C99 does and Lua’s source code are C89-compliment. I suspect Roblox compiled Luau using some sort of C89-compliment C compiler or that it parses the literal as an 64-bit unsigned integer first as I know that C99 introduced hexadecimal floats. Either way I’m certain that the hexadecimal literal parsed as an 32/64-bit unsigned integer in some implementions of Lua 5.1.
This bug is certainly patched in Lua 5.2 along with the introduction of hexadecimal floats and hexadecimal exponent literal.
Right now, the bug can both be found on the Studio and in-game; for the reproduction, run this part of code in somewhere in Roblox. Doesn’t matter whether it’s a server script or a client script, they both return the exact same result.
local v = 0x10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
if v == 4294967295 then
print("This bug is not patched - 32-bit unsigned integer")
elseif v == 2 ^ 64 - 1 then
print("This bug is not patched - 64-bit unsigned integer")
elseif v == math.huge then
print("This bug has been patched on the version of Lua used")
else
print(string.format("This bug is not patched or it's interpreted as a true integer - This literal is parsed either as a true integer, as an integer that either clamps at %.0f or as floating point format more precise than IEEE 754 double precision", v))
end
This doesn’t apply to hexadecimal value in tonumber
in Roblox’s Lua ergo, in Luau this doesn’t equal even though they’re both the same value logically:
print(0x10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ~= tonumber("0x10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"))
but inserting this hexdecimal value into tonumber
is still capped at 232/264 for PUC-Rio Lua 5.1.
To conclude this is a bug spanning only in some platforms of Lua 5.1 (I guess if compiled with C89); the bug only persists on Lua implementions where hexadecimal floats and exponents aren’t supported (coincidentally) so tonumber
in Luau doesn’t have this bug; Roblox’s Luau for hexadecimal literal is one of them as if you type in print(0x10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000)
into a script/command bar, it’ll incorrectly parse as 1.844674407371e+19
rather than inf
. This also applies to binary literals.