跨平台/编译器一致的浮点数冲刺
Cross platform/compiler consistent sprintf of floating point numbers
我们有一款需要确定性的游戏,因为它是多人模式的一部分。我们还使用Lua,它内部使用sprintf
(格式为%.14g
)。
当它打印像0.00001这样的数字时,问题出现了。在某些情况下,它打印1e-05
,在其他情况下,它打印1e-005
(额外的零)。
例如,在Visual studio 2015中编译时,它打印1e-005
,在Visual studio 2013中打印1e-05
。我尝试了不同的语言环境设置,但似乎没有任何效果。
问题是:实现确定性结果的最佳解决方案是什么?我真的不在乎科学符号是标准化了,还是被淘汰了。
我想到的解决方案:
- 当我使用
%f
符号时,它不会忽略无关紧要的零,因此使用%.14f
将导致不切实际的长数字。 - 使用自定义
sprintf
方法(从一些标准库复制粘贴) - 使用一些我没有想到的特殊格式(我只使用这个作为参考:http://www.cplusplus.com/reference/cstdio/printf/)
您可以切换到LuaJIT。它在不同平台之间保持数字格式的一致性。
从扩展页:
tostring()等规范化NaN和±Inf
所有数字到字符串的转换在所有平台上一致地将非有限数字转换为相同的字符串。NaN的结果是" NaN ",正无穷的结果是"inf"而负无穷大的结果是"-inf"
tonnumber()等使用内置字符串到数字的转换
在所有平台上,所有字符串到数字的转换都一致地转换十进制和十六进制的整数和浮点输入。不再使用strtod(),这避免了由于C库实现不佳而导致的许多问题。内置转换功能根据IEEE-754标准提供全精度,它独立于当前区域设置工作,并支持十六进制浮点数(例如0x1.5p-3)。
投票最多的答案是错误的,因为文档首先是错误的。
这是在LuaJIT中发生的事情:
#define lua_number2str(s,n)sprintf((s),"%.14g",(n))
#define lua_str2number(s,p)strtod((s),(p))
看看tonumber
和tostring
的实现,它们是用来获取结果的宏。
如果你找到了真正的"内置"实现,请随意更正这个答案,因为我也很好奇它是如何工作的
一年后,我们就是这样解决的。
我们下载了自定义打印实现(trio),并强制使用该实现而不是lua(和我们的源代码)中的系统实现。
我们还必须更改
long double trio_long_double_t;
double trio_long_double_t;
,以确保Visual studio和linux/mac给出相同的结果
Lua为您提供了标准库中的math.frexp。您可以使用它将浮点数拆分为指数和尾数形式,然后使用不依赖于底层平台的纯Lua进行自定义打印。下面是一个例子:
m,e = math.frexp(val)
io.write(m)
io.write('E')
io.write(e)
PS享受星期五的事实,让他们继续:)
- 在C++中,将大的无符号浮点数四舍五入为整数的最佳方法是什么
- 如何修复此错误:未定义对"距离(浮点数,浮点数,浮点数,浮点数,浮点数)"的引用
- C++浮点数据类型和字符串数据类型无法子到模板函数中
- 使用提升将数据从 PyObject 复制到浮点数 *
- 使用浮点数和双精度数的非常小数字的数学
- 使用英特尔内联函数将打包的 8 位整数乘以浮点数向量
- 如何在 c++ 中将小数点后两位数的浮点数分配给另一个浮点数
- 返回浮点数的小数位数
- txt 文件中浮点数的最大和最小值
- 为什么 std::cout 打印浮点数、双精度和长双精度到相同的小数精度?
- 将浮点数转换为无符号字符数组并打印出来
- 如何将时间字符串 (M:SS) 转换为浮点数
- 如何将浮点数(*)[6]转换为浮点**类型?
- C++将浮点数乘以分数
- 如何将浮点数转换为uint8_t?
- 将字符串转换为浮点数或整数,而无需使用内置函数(如 atoi 或 atof)
- 如何在C++(Arduino)中将浮点数组转换为字节数组
- 在数学上将浮点数四舍五入到 N 位小数
- Cython通过浮点数的最快方式,用于高频控制回路
- 跨平台/编译器一致的浮点数冲刺