Lua 5.1.4中string.format用%d格式化长数字串结果异常问题
问题现象
- 运行环境:Lua 5.1.4
Lua 5.1.4 Copyright (C) 1994-2008 Lua.org, PUC-Rio
使用%d作为格式化占位符时,执行代码:
print(string.format("where id = %d", "1596856742980208710"))
得到输出:
where id = 1596856742980208640
输出数值和传入的原始字符串代表的数值存在明显偏差。
将占位符替换为%s后,执行代码:
print(string.format("where id = %s", "1596856742980208710"))
得到输出:
where id = 1596856742980208710
输出内容与原始传入值完全一致。
产生原因
这个现象是Lua 5.1的数值类型设计+双精度浮点数精度限制共同导致的,核心逻辑如下:
- Lua 5.1 没有独立的整数类型,所有数值统一使用双精度浮点数(double)存储。双精度浮点数的有效整数精度为53个二进制位,对应十进制下仅能精确表示小于253(约9.007×1015)的整数;一旦数值超过这个范围,相邻两个可精确表示的浮点数间隔会大于1,无法做到每个整数都一一对应,转换时必然出现精度丢失。
- 当
string.format使用%d占位符时,会强制将传入的参数转换为number类型处理。示例中传入的字符串对应的数值为1596856742980208710,量级远大于2^53,转换为双精度浮点数时无法精确匹配原值,只能就近取到可被精确表示的最近值1596856742980208640,最终输出就出现了偏差。 - 当
string.format使用%s占位符时,不会触发数值类型转换,会直接将传入的字符串参数原样拼接到格式化结果中,原始值没有经过任何转换计算,自然不会出现精度丢失,输出和传入值完全一致。
注:如果在Lua 5.1环境下处理雪花ID这类超过16位的大整数,全程按字符串存储处理是最稳妥的方案,不要随意转成number类型,否则很容易出现精度错乱的问题。
内容的提问来源于stack exchange,提问作者Lucas Au
相关产品推荐
相关产品推荐

