Lua version is 5.1.4, here is the details:
Lua 5.1.4 Copyright (C) 1994-2008 Lua.org, PUC-Rio
print(string.format("where id = %d", "1596856742980208710"))
output:
where id = 1596856742980208640
But when changing %d
to %s
:
print(string.format("where id = %s", "1596856742980208710"))
output:
where id = 1596856742980208710
What does this mean?
This is a Lua "feature" called coercion: Lua will coerce strings to numbers if a number is expected and vice versa. Lua 5.1 by default uses doubles as only number type, which may lead to a loss of precision when coercing large numbers.
Consider your first example:
print(string.format("where id = %d", "1596856742980208710"))
%d
obviously expects a number. The string "1596856742980208710"
is thus coerced to a number; the code is equivalent to
print(string.format("where id = %d", tonumber"1596856742980208710"))
on newer Lua versions (5.3+), this would work just fine, since the number would be converted to a 64-bit signed integer:
$ lua
Lua 5.3.4 Copyright (C) 1994-2017 Lua.org, PUC-Rio
> tonumber"1596856742980208710"
1596856742980208710
Lua 5.1 does however not have an integer type; it will convert the number to a 64-bit double:
$ lua5.1
Lua 5.1.5 Copyright (C) 1994-2012 Lua.org, PUC-Rio
> =("%d"):format(tonumber"1596856742980208710")
1596856742980208640
as you can see, the number has changed. This is because of double precision issues: The maximum safe integer that can be stored in a double is 2^53 - 1 (see e.g. JS's MAX_SAFE_INTEGER
). Your number significantly exceeds that: Compare 9.007199254741e+15
against 1596856742980208710
. This leads to a loss of precision in the less significant decimal places. When the number is then formatted using %d
, you get the incorrect result.
Your second example:
print(string.format("where id = %s", "1596856742980208710"))
obviously works, since it treats "1596856742980208710"
as a string and doesn't coerce it to a number in the first place. It is thus equivalent to a string concatenation "where id = " .. "1596856742980208710"
no matter the Lua version (as "1596856742980208710"
doesn't contain NULL bytes).