交叉platform/compiler浮点数的一致sprintf

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。我尝试了不同的语言环境设置,但似乎没有任何效果。

问题是:实现确定性结果的最佳解决方案是什么? 我真的不在乎科学计数法是标准化的还是被淘汰的。

我想到的解决方案:

您可以切换到 LuaJIT。它在平台之间以一致的方式格式化数字。

来自extensions page

tostring() etc. canonicalize NaN and ±Inf

All number-to-string conversions consistently convert non-finite numbers to the same strings on all platforms. NaN results in "nan", positive infinity results in "inf" and negative infinity results in "-inf".

tonumber() etc. use builtin string to number conversion

All string-to-number conversions consistently convert integer and floating-point inputs in decimal and hexadecimal on all platforms. strtod() is not used anymore, which avoids numerous problems with poor C library implementations. The builtin conversion function provides full precision according to the IEEE-754 standard, it works independently of the current locale and it supports hex floating-point numbers (e.g. 0x1.5p-3).

Lua 在标准库中为您提供 math.frexp。您可以使用它将浮点数拆分为指数和尾数形式,然后以不依赖于底层平台的纯 Lua 进行自定义打印。这是一个例子:

m,e = math.frexp(val)
io.write(m)
io.write('E')
io.write(e)

PS 享受周五的事实,让他们来:)

投票最多的答案是错误的,因为文档首先是错误的。

这就是 LuaJIT 中正在发生的事情:

#define lua_number2str(s,n)sprintf((s),"%.14g",(n))
#define lua_str2number(s,p)strtod((s),(p))

查看 tonumbertostring 实现,这些是为获得结果而调用的宏。

如果您找到真正的 "built-in" 实现,请随时更正此答案,因为我也很好奇它是如何工作的。

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

我们下载了自定义打印实现(三重奏)并强制使用此实现而不是 lua(和我们的来源)中的系统。

我们也不得不改变

long double trio_long_double_t;

double trio_long_double_t;

在 triodef.h 中确保 Visual studio 和 linux/mac 给出相同的结果。