We have a game that needs to be deterministic as it is part of its multiplayer model. We also use Lua, which uses the sprintf
internally (the format is %.14g
).
The problem arises when it prints number like 0.00001. In some cases it prints 1e-05
and in some other cases, it prints 1e-005
(extra zero).
For example when compiled with Visual studio 2015 it prints 1e-005
, and with Visual studio 2013 it prints 1e-05
. I tried different locale settings, but it doesn't seem to have any effect.
The question is: What is the best solution to achieve deterministic results? I don't really care if the scientific notation is standardized, or eliminated.
Solutions I thought about:
%f
notation, it doesn't ignore the insignificant zeroes, so having %.14f
would result into impractically long numbers.sprintf
method (copy pasted from some of the standard libraries)You can switch to LuaJIT. It formats numbers consistently between platforms.
From the 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).
The most voted answer is wrong, because the documentation is wrong in first place.
This is what's happening in LuaJIT:
#define lua_number2str(s,n)sprintf((s),"%.14g",(n))
#define lua_str2number(s,p)strtod((s),(p))
Looking at tonumber
and tostring
implementation those are the macros called to get the results.
Feel free to correct this answer if you find the real "built-in" implementation, cause I'm curious as well to know how it really works.
A year later, this is how we solved it.
We downloaded custom print implementation (trio) and forced usage of this implementation instead of the system one in the lua (and our sources).
We also had to change
long double trio_long_double_t;
to
double trio_long_double_t;
in the triodef.h to ensure the Visual studio and linux/mac gives the same results.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With