Pregunta

Ver este código:

<html>
  <head> 
    <script src="http://www.json.org/json2.js" type="text/javascript"></script>
    <script type="text/javascript">

      var jsonString = '{"id":714341252076979033,"type":"FUZZY"}';
      var jsonParsed = JSON.parse(jsonString);
      console.log(jsonString, jsonParsed);

    </script>
  </head>
  <body>
  </body>
</html>

Cuando veo a mi consola en Firefox 3.5, el valor de jsonParsed es:

Object id=714341252076979100 type=FUZZY

I. e el número se redondea.Trató de valores diferentes, el mismo resultado (número redondeado).

Yo también no consigue sus reglas de redondeo.714341252076979136 se redondea a 714341252076979200, mientras que 714341252076979135 se redondea a 714341252076979100.

EDITAR: Ver primer comentario a continuación.Al parecer, esto no es acerca de JSON, pero algo acerca de JavaScript en el manejo de las cifras.Pero la pregunta sigue siendo:

¿Por qué está sucediendo esto?

¿Fue útil?

Solución

Lo que estamos viendo aquí es en realidad el efecto de dos redondeos. Los números en ECMAScript se representan internamente de doble precisión de punto flotante. Cuando se establece en id 714341252076979033 (0x9e9d9958274c359 en hexadecimal), que en realidad se le asigna el valor de doble precisión representable más cercano, que es 714341252076979072 (0x9e9d9958274c380). Cuando se imprime el valor, que se redondea a 15 dígitos decimales significativos, lo que da 14341252076979100.

Otros consejos

Usted está desbordando la capacidad del tipo de número de JavaScript, consulte § 8.5 de la especificación para más detalles. Esas identificaciones tendrán que ser cadenas.

IEEE-754 de doble precisión en coma flotante (el tipo de número utiliza JavaScript) no puede representar con precisión todos los los números (por supuesto). Lo conocido, 0.1 + 0.2 == 0.3 es falsa. Que pueden afectar a los números enteros al igual que afecta a los números fraccionarios; se inicia una vez que llegue por encima de 9,007,199,254,740,991 (Number.MAX_SAFE_INTEGER).

Más allá de Number.MAX_SAFE_INTEGER + 1 (9007199254740992), el formato de punto flotante IEEE-754 ya no puede representar a cada número entero consecutivo. 9007199254740991 + 1 es 9007199254740992, pero 9007199254740992 + 1 es también 9007199254740992 porque 9007199254740993 no puede ser representado en el formato. El siguiente es que puede ser 9007199254740994. Entonces 9007199254740995 no puede ser, pero 9007199254740996 lata.

La razón es que hemos quedado sin bits, por lo que ya no tienen un poco 1s; el bit de orden más bajo ahora representa múltiplos de 2. Finalmente, si tenemos en marcha, perdemos ese poco y sólo el trabajo en múltiplos de 4. Y así sucesivamente.

Sus valores son y por encima de ese umbral, y así consiguen redondeado al valor representable más cercano.


Si eres curioso acerca de los bits, esto es lo que sucede: Un número binario de coma flotante de doble precisión IEEE-754 tiene un bit de signo, 11 bits de exponente (que define la escala global de la serie, como un poder de 2 [porque se trata de un formato binario]), y 52 bits de mantisa (pero el formato es tan inteligente que se pone 53 bits de precisión fuera de esos 52 bits). ¿Cómo se complica el exponente se utiliza ( descrito aquí ), pero en muy términos vagos, si añadimos uno al exponente, el valor de la mantisa se duplica, ya que el exponente se utiliza para potencias de 2 (de nuevo, salvedad ahí, es más que directo, no hay inteligencia allí).

Así que vamos a ver el valor 9007199254740991 (aka, Number.MAX_SAFE_INTEGER):

   +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− sign bit
  / +−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− exponent
 / /        |  +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+− significand
/ /         | /                                                  |
0 10000110011 1111111111111111111111111111111111111111111111111111
                = 9007199254740991 (Number.MAX_SAFE_INTEGER)

Ese valor del exponente, 10000110011, significa que cada vez que añadimos una a la mantisa, el número representado sube por 1 (el número entero 1, hemos perdido la capacidad de representar números fraccionarios mucho antes).

Pero ahora que significand está lleno. Para ir más allá de ese número, tenemos que aumentar el exponente, lo que significa que si añadimos una a la mantisa, el valor del número representado sube por 2, no 1 (ya que el exponente se aplica a 2, la base de este número de punto flotante binario):

   +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− sign bit
  / +−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− exponent
 / /        |  +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+− significand
/ /         | /                                                  |
0 10000110100 0000000000000000000000000000000000000000000000000000
                = 9007199254740992 (Number.MAX_SAFE_INTEGER + 1)

Bueno, eso está bien, porque se 9007199254740991 + 1 9007199254740992 de todos modos. ¡Pero! No podemos representar 9007199254740993. Nos hemos quedado sin bits. Si añadimos a sólo 1 a la mantisa, que añade 2 al valor:

   +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− sign bit
  / +−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− exponent
 / /        |  +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+− significand
/ /         | /                                                  |
0 10000110100 0000000000000000000000000000000000000000000000000001
                = 9007199254740994 (Number.MAX_SAFE_INTEGER + 3)

El formato no puede representar números impares más a medida que aumenta el valor, el exponente es demasiado grande.

Finalmente, nos acaba de bits de mantisa de nuevo y tener que aumentar el exponente, por lo que terminan sólo ser capaz de representar múltiplos de 4. Luego múltiplos de 8. Entonces múltiplos de 16. Y así sucesivamente.

No es causada por este analizador JSON. Sólo trata de introducir 714341252076979033 a la consola de fbug. Verá el mismo 714341252076979100.

Vea esta entrada del blog para más detalles: http://www.exploringbinary.com/print-precision -de-punto flotante enteros-varía demasiado

JavaScript se utiliza coma flotante de doble precisión de los valores, es decir, un total de precisión de 53 bits, pero usted necesita

ceil(lb 714341252076979033) = 60

bits para representar exactamente el valor.

El más cercano exactamente representable número es 714341252076979072 (escriba el número original en binario, reemplazar los últimos 7 dígitos con 0 y ronda debido a la mayor reemplazado dígitos fue 1).

Usted obtendrá 714341252076979100 en lugar de este número, porque ToString() como se describe por ECMA-262, §9.8.1 trabaja con potencias de diez y en el 53 bits de precisión de todos estos números son iguales.

El problema es que su número, se necesita una precisión mayor que tiene JavaScript.

¿Se puede enviar el número como una cadena? Separado en dos partes?

JavaScript sólo puede manejar números enteros exactos hasta cerca de 9000 millones de millones (que es 9 con 15 ceros). Más alta que la basura y se obtiene. Evitar esto usando cuerdas para mantener los números. Si necesita hacer cálculos con estos números, escribir sus propias funciones o ver si se puede encontrar una biblioteca para ellos: Sugiero a los primeros como no me gustan las bibliotecas que he visto. Para empezar, ver a dos de mis funciones en otra respuesta .

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top