javascript - que - onclick void 0
2.9999999999999999>>.5? (11)
El operador de desplazamiento a la derecha solo opera en enteros (en ambos lados). Por lo tanto, desplazar a la derecha en .5 bits debería ser exactamente equivalente a desplazar a la derecha en 0 bits. Y, el lado izquierdo se convierte en un entero antes de la operación de cambio, que hace lo mismo que Math.floor ().
Escuché que podrías desplazar hacia la derecha un número en .5 en lugar de usar Math.floor (). Decidí verificar sus límites para asegurarme de que era un reemplazo adecuado, así que revisé los siguientes valores y obtuve los siguientes resultados en Google Chrome:
2.5 >> .5 == 2;
2.9999 >> .5 == 2;
2.999999999999999 >> .5 == 2; // 15 9s
2.9999999999999999 >> .5 == 3; // 16 9s
Después de tocar un poco, descubrí que el valor más alto posible de dos que, cuando se desplaza a la derecha por .5, daría 2 es 2.9999999999999997779553950749686919152736663818359374999999 (con la repetición de 9) en Chrome y Firefox. El número es 2.9999999999999997779¯ en IE.
Mi pregunta es: ¿cuál es el significado del número .0000000000000007779553950749686919152736663818359374? Es un número muy extraño y realmente despertó mi curiosidad.
He estado tratando de encontrar una respuesta o al menos algún tipo de patrón, pero creo que mi problema radica en el hecho de que realmente no entiendo la operación bit a bit. Entiendo la idea en principio, pero cambiar una secuencia de bits por .5 no tiene ningún sentido para mí. Cualquier ayuda es apreciada.
Para el registro, la extraña secuencia de dígitos cambia con 2 ^ x. Los valores más altos posibles de los siguientes números que todavía se truncan correctamente:
for 0: 0.9999999999999999444888487687421729788184165954589843749¯ for 1: 1.9999999999999999888977697537484345957636833190917968749¯ for 2-3: x+.99999999999999977795539507496869191527366638183593749¯ for 4-7: x+.9999999999999995559107901499373838305473327636718749¯ for 8-15: x+.999999999999999111821580299874767661094665527343749¯ ...and so forth
Esta es posiblemente la peor idea que he visto en mi vida. Su único propósito posible para existir es ganar un concurso de código ofuscado. No hay importancia para los números largos que publicaste: son un artefacto de la implementación de coma flotante subyacente, filtrada a través de Dios sabe cuántas capas intermedias. El cambio de bits por un número fraccionario de bytes es una locura y me sorprende que no genere una excepción, pero eso es Javascript, siempre dispuesto a redefinir "locura".
Si yo fuera tú, evitaría usar esta "característica". Su único valor es como una posible causa raíz para una condición de error inusual. Use Math.floor()
y tenga compasión del próximo programador que mantendrá el código.
Confirmando un par de sospechas que tuve al leer la pregunta:
- Desplazando a la derecha cualquier número fraccionario
x
por cualquier número fraccionarioy
simplemente truncaráx
, dando el mismo resultado queMath.floor()
mientras confunde completamente al lector. - 2.999999999999999777955395074968691915 ... es simplemente el número más grande que se puede diferenciar de "3". Intente evaluarlo por sí mismo: si agrega algo, se evaluará a 3. Esto es un artefacto del navegador y de la implementación en coma flotante del sistema local.
No creo que tu cambio correcto sea relevante. Simplemente está más allá de la resolución de una constante de punto flotante de doble precisión.
En Chrome:
var x = 2.999999999999999777955395074968691915273666381835937499999;
var y = 2.9999999999999997779553950749686919152736663818359375;
document.write("x=" + x);
document.write(" y=" + y);
Imprime: x = 2.9999999999999996 y = 3
Pruebe este javascript out: alerta (parseFloat ("2.9999999999999997779553950749686919152736663818359374999999"));
Luego intente esto: alerta (parseFloat ("2.9999999999999997779553950749686919152736663818359375"));
Lo que está viendo es simple imprecisión en coma flotante. Para obtener más información al respecto, consulte esto, por ejemplo: http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems .
El problema básico es que lo más cercano que un valor de coma flotante puede llegar a representar el segundo número es mayor o igual que 3, mientras que el cierre que puede alcanzar el primer número es estrictamente menor que tres.
En cuanto a por qué el cambio a la derecha por 0.5 hace que todo cuerdo en absoluto, parece que 0.5 solo se está convirtiendo a un int (0) de antemano. Entonces el flotador original (2.999 ...) se convierte a un int por truncamiento, como de costumbre.
Si quieres profundizar, lee "Lo que todo científico informático debe saber sobre la aritmética de coma flotante": http://docs.sun.com/source/806-3568/ncg_goldberg.html
Supongo que obtendrás los mismos resultados simplemente transfiriendo los valores a ints.
Y para agregar a la respuesta de John, las probabilidades de que esto sea más eficiente que Math.floor son infinitamente pequeñas.
No sé si JavaScript usa números de punto flotante o algún tipo de biblioteca de precisión infinita, pero de cualquier forma, obtendrá errores de redondeo en una operación como esta, incluso si está bastante bien definida.
Cabe señalar que el número ".0000000000000007779553950749686919152736663818359374" es muy posiblemente el Epsilon , definido como "el número más pequeño E tal que (1 + E)> 1."
Sospecho que la conversión de 2.9999999999999997779553950749686919152736663818359374999999 a su representación binaria sería esclarecedor. Probablemente solo sea 1 bit diferente de True 3.
Buena suposición, pero no cigarro. Como el número FP de doble precisión tiene 53 bits, el último número FP anterior a 3 es en realidad (exacto): 2.999999999999999555910790149937383830547332763671875
Pero por qué es 2.9999999999999997779553950749686919152736663818359375
(¡y esto es exacto, no 49999 ...!)
que es más alto que la última unidad visualizable? Redondeo La rutina de conversión (String to number) simplemente está programada correctamente para redondear la entrada el siguiente número de coma flotante.
2.999999999999999555910790149937383830547332763671875
....... (valores entre, aumentar) -> redondear hacia abajo
2.9999999999999997779553950749686919152736663818359375
....... (valores entre, aumentar) -> redondear hasta 3
3
La entrada de conversión debe usar una precisión total. Si el número es exactamente la mitad entre esos dos números de fp (que es 2.9999999999999997779553950749686919152736663818359375) el redondeo depende de los indicadores establecidos. El redondeo predeterminado es redondo a par, lo que significa que el número se redondeará al siguiente número par.
Ahora
3 = 11. (binario)
2.999 ... = 10.11111111111 ...... (binario)
Todos los bits están configurados, el número siempre es impar. Eso significa que el número medio exacto se redondeará hacia arriba, por lo que está obteniendo el período extraño de 49999 porque debe ser más pequeño que la mitad exacta para poder distinguirse de 3.
En realidad, simplemente terminas haciendo un piso () en el primer operando, sin que haya operaciones de punto flotante. Como las operaciones de desplazamiento hacia la izquierda y hacia la derecha solo tienen sentido con operandos enteros, el motor de JavaScript convierte primero los dos operandos en enteros:
2.999999 >> 0.5
Se convierte en:
Math.floor(2.999999) >> Math.floor(0.5)
Que a su vez es:
2 >> 0
Cambiar por 0 bits significa "no hacer un cambio" y, por lo tanto, terminas con el primer operando, simplemente truncado en un entero.
El código fuente de SpiderMonkey tiene:
switch (op) {
case JSOP_LSH:
case JSOP_RSH:
if (!js_DoubleToECMAInt32(cx, d, &i)) // Same as Math.floor()
return JS_FALSE;
if (!js_DoubleToECMAInt32(cx, d2, &j)) // Same as Math.floor()
return JS_FALSE;
j &= 31;
d = (op == JSOP_LSH) ? i << j : i >> j;
break;
Si ve un "resumen" con ciertos números se debe al hecho de que el motor JavaScript no puede manejar los dígitos decimales más allá de cierta precisión y, por lo tanto, su número termina siendo redondeado al siguiente entero. Prueba esto en tu navegador:
alert(2.999999999999999);
Obtendrás 2.999999999999999. Ahora intenta agregar uno más 9:
alert(2.9999999999999999);
Obtendrás un 3.
Sospecho que la conversión de 2.9999999999999997779553950749686919152736663818359374999999 a su representación binaria sería esclarecedora. Probablemente solo sea 1 bit diferente de True 3.