Pregunta Cross plataforma / compilador sprintf consistente de números de coma flotante


Tenemos un juego que debe ser determinista ya que es parte de su modelo multijugador. También usamos Lua, que usa el sprintf internamente (el formato es %.14g)

El problema surge cuando imprime un número como 0.00001. En algunos casos, imprime 1e-05 y en algunos otros casos, imprime 1e-005 (cero adicional).

Por ejemplo, cuando se compila con Visual Studio 2015 imprime 1e-005y con Visual Studio 2013 imprime 1e-05. Intenté diferentes ajustes de configuración regional, pero parece que no tiene ningún efecto.

La pregunta es: ¿Cuál es la mejor solución para lograr resultados deterministas? Realmente no me importa si la notación científica está estandarizada o eliminada.

Soluciones en las que pensé:

  • Cuando uso el %f notación, no ignora los ceros insignificantes, por lo que %.14f daría como resultado números demasiado largos.
  • Usando personalizado sprintf método (copia pegada de algunas de las bibliotecas estándar)
  • Utilicé un formato especial en el que no pensé (solo uso esto como referencia: http://www.cplusplus.com/reference/cstdio/printf/)

32
2017-10-16 14:55


origen


Respuestas:


Puedes cambiar a LuaJIT. Formatea los números consistentemente entre plataformas.

Desde el página de extensiones:

tostring () etc. canonicalizar NaN y ± Inf

Todas las conversiones de número a cadena convierten consistentemente números no finitos a las mismas cadenas en todas las plataformas. NaN da como resultado "nan", el infinito positivo da como resultado "inf" y el infinito negativo da como resultado "-inf".

tonumber () etc. usa cadena integrada para conversión de números

Todas las conversiones de cadena a número convierten constantemente las entradas de coma flotante y entera en decimal y hexadecimal en todas las plataformas. strtod () ya no se usa, lo que evita numerosos problemas con implementaciones pobres de la biblioteca C. La función de conversión integrada proporciona una precisión total de acuerdo con el estándar IEEE-754, funciona independientemente de la configuración regional actual y admite números hexadecimales de coma flotante (por ejemplo, 0x1.5p-3).


18
2017-10-16 17:44



La respuesta más votada es incorrecta, porque la documentación es incorrecta en primer lugar.

Esto es lo que está sucediendo en LuaJIT:

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

Mirando a tonumber y tostring implementación esas son las macros llamadas para obtener los resultados.

No dude en corregir esta respuesta si encuentra la verdadera implementación "incorporada", porque también tengo curiosidad por saber cómo funciona realmente.


4
2017-09-13 11:43



Un año después, así es como lo resolvimos.

Descargamos la implementación de impresión personalizada (trío) y el uso forzado de esta implementación en lugar del sistema uno en el lua (y nuestras fuentes).

También tuvimos que cambiar

long double trio_long_double_t;

a

double trio_long_double_t;

en el triodef.h para garantizar que Visual Studio y linux / mac den los mismos resultados.


3
2017-10-04 12:53



Lua te da math.frexp en la biblioteca estándar. Puede usar esto para dividir sus flotantes en forma de exponente y mantisa, y luego hacer una impresión personalizada en Lua puro que no dependerá de la plataforma subyacente. Aquí hay un ejemplo:

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

PD: Disfrutando los hechos del viernes, sigan viniendo :)


1
2018-05-15 13:13