跨平台/编译器一致的浮点数冲刺

Cross platform/compiler consistent sprintf of floating point numbers

本文关键字:浮点数 冲刺 编译器 跨平台      更新时间:2023-10-16

我们有一款需要确定性的游戏,因为它是多人模式的一部分。我们还使用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))

看看tonumbertostring的实现,它们是用来获取结果的宏。

如果你找到了真正的"内置"实现,请随意更正这个答案,因为我也很好奇它是如何工作的

一年后,我们就是这样解决的。

我们下载了自定义打印实现(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享受星期五的事实,让他们继续:)