2011-08-07 11 views
11

Python version | Javascript version | Whitepaperaritmética de punto flotante Python vs Javascript dando respuestas muy diferentes. ¿Qué estoy haciendo mal?

Por lo tanto, estoy trabajando en un sitio web para calcular las clasificaciones de Glicko para juegos de dos jugadores. Implica una gran cantidad de aritmética de coma flotante (raíces cuadradas, exponentes, división, todas las cosas desagradables) y, por alguna razón, recibo una respuesta completamente diferente de la implementación de Python del algoritmo que traduje línea por línea. La versión de Python está dando básicamente la respuesta esperada para el ejemplo encontrado en el documento original que describe el algoritmo, pero la versión de Javascript está bastante desfasada.

¿He cometido un error de traducción o las matemáticas de punto flotante de Javascript son menos precisas?

Expected answer: [1464, 151.4] 
Python answer: [1462, 155.5] 
Javascript answer: [1470.8, 89.7] 

Así que el cálculo de la calificación no es TAN malo, siendo 99.6% exacto, pero la varianza está desactivada en 2/3!

Editar: La gente ha señalado que el valor predeterminado de RD en la versión Pyglicko es 200. Este es un caso del implementador original que deja en código de prueba, creo, ya que el caso de prueba se realiza en una persona con un RD de 200, pero claramente se supone que el valor predeterminado es 350. Sin embargo, especifiqué 200 en mi caso de prueba en Javascript, por lo que ese no es el problema aquí.

Editar: Se modificó el algoritmo para usar map/reduce. La calificación es menos precisa, la varianza es más precisa, ambas sin motivo aparente. Comienza el wallbanging.

+1

Esto es probable porque Python y JavaScript no manejan los números de punto flotante de la misma manera. ¿Sabes cómo funcionan los números flotantes?(y cuando no lo hacen) – Halcyon

+2

No sé si esto tiene algún significado, pero rd tiene por defecto 200 en python y 350 en javascript. @Frits: ambos usan IEEE 754. –

+0

Sí, entiendo cómo funcionan los números flotantes y que, por ejemplo, no pueden representar números decimales exactamente. @Daniel Baulig: RD tiene un valor predeterminado de 200 en Python, que es incorrecto, pero se usa para el caso de prueba. En el documento técnico, se especifica que el RD se establece en 350, pero el caso de prueba es en un reproductor con un RD de 200, así que establecí el valor por defecto adecuado en Javascript pero llamé a un nuevo jugador en el caso de prueba con un RD de 200 –

Respuesta

7

Normalmente se obtienen errores como este en los que se restan dos números similares; a continuación, se amplifican las diferencias normalmente insignificantes entre los valores. por ejemplo, si tiene dos valores que son 1.2345 y 1.2346 en python, pero 1.2344 y 1.2347 en javascript, entonces las diferencias son 1e-4 y 3 e-4 respectivamente (es decir, una es 3 veces la otra).

para ver dónde tienes sustracciones en tu código y verificar esos valores. puede encontrar que puede (1) reescribir las matemáticas para evitar la resta (a menudo resulta que puede encontrar una expresión que calcula la diferencia de alguna otra manera) o (2) enfocarse en por qué los valores en ese punto particular difieren entre los dos idiomas (tal vez la diferencia en pi que la otra respuesta identificó se está amplificando de esta manera).

también es posible, aunque es menos probable aquí, que tenga una diferencia porque algo se trata como un número entero en python, pero como un flotador en javascript. en python hay una diferencia entre enteros y flotantes, y si no tiene cuidado puede hacer cosas como dividir dos enteros para obtener otro entero (por ejemplo, 3/2 = 1 en python). mientras que en javascript, todos los números son flotantes "realmente", por lo que esto no ocurre.

Finalmente, es posible que existan pequeñas diferencias en la forma en que se realizan los cálculos. pero estos son "normales": para obtener diferencias tan drásticas, es necesario que ocurra algo similar a lo que describí anteriormente.

PD: también tenga en cuenta lo que dijo Daniel Baulig sobre el valor inicial del parámetro rd en los comentarios anteriores.

+0

Dado que ambos lenguajes usan IEEE 754 como implementación de punto flotante, no veo cómo la misma entrada podría producir dos números diferentes en cualquier sistema. Estoy bastante seguro de que Kindall está señalando algo muy significativo. En el código de JavaScript, PI solo se aproxima muy aproximadamente, mientras que en el código de Python se usa la constante de Matemáticas. Esto conducirá a resultados muy incorrectos. –

+1

hay dos problemas separados. existe la cuestión de duplicar exactamente los resultados, pero también de implementar el cálculo de una manera estable. Si obtiene resultados que varían enormemente según la cantidad de dígitos significativos que tenga en PI, eso sugiere que el sistema en su conjunto está mal acondicionado. podría ser que al forzar que PI sea exactamente igual, el que pregunta original puede obtener resultados idénticos en ambos casos, pero aún tendrá un código cuestionable. por otro lado, si comprende mejor las inestabilidades, realmente puede mejorar lo que tiene. –

+1

también ieee no es perfecto. ver comentarios en http://en.wikipedia.org/wiki/IEEE_754-2008#Reproducibility - no tengo idea de cuán cerca está una implementación perfecta, o si usan las mismas librerías, pero esperan resultados idénticos a bit en idénticos la entrada es un poco optimista. –

2

Supongo que se trata de las aproximaciones que está utilizando para algunas de las constantes en la versión de JavaScript. Su pi2 en particular parece un poco ... breve. Creo que Python está usando dobles para esos valores.

+0

Probé su código en node.js usando Math.PI^2 - todavía obtuve 1470.8 – Alnitak

+0

Originalmente tenía Math.whatever para todas las constantes, y en el medio de la resolución de problemas las reemplacé con los valores de las constantes realmente usadas para calcular en el libro blanco (5 cifras significativas, en general). –

Cuestiones relacionadas