ruby floating-point negative-zero

¿Por qué tenemos 0.0 y-0.0 en Ruby?



floating-point negative-zero (4)

Es porque todos los números de coma flotante IEEE 754 tienen un bit de signo para indicar si un número es positivo o negativo.

Aquí están las representaciones binarias de 2.5 y -2.5 :

[2.5].pack(''f'').unpack1(''b*'') #=> "00000000000000000000010000000010" [-2.5].pack(''f'').unpack1(''b*'') #=> "00000000000000000000010000000011"

El último bit es el bit de signo, tenga en cuenta que todos los demás bits son idénticos.

Por otro lado, hay cero con el bit de signo establecido en 0 :

[''00000000000000000000000000000000''].pack(''b*'').unpack1(''f'') #=> 0.0

y cero con bit de signo establecido en 1 :

[''00000000000000000000000000000001''].pack(''b*'').unpack1(''f'') #=> -0.0

Aunque 0.0 y -0.0 son numéricamente iguales, no son idénticos en el nivel de objeto:

(0.0).eql?(-0.0) #=> true (0.0).equal?(-0.0) #=> false

y hay algunas propiedades especiales cuando se trabaja con cero negativo, por ejemplo:

1 / 0.0 #=> Infinity 1 / -0.0 #=> -Infinity

Asignación - explícitamente no es la única forma de obtener -0.0 . También puede obtenerlo como resultado de una operación aritmética básica:

-1.0 * 0 #=> -0.0

Esta pregunta ya tiene una respuesta aquí:

En ruby, ¿por qué puedo asignar un signo negativo a 0.0 float? ¿Esta función es útil de alguna manera? ¿Podría alguien explicarme esto?

-0.0 #=> -0.0 -0.0 * -1 #=> 0.0


Las operaciones matemáticas tienen resultados de números reales, pero asignamos esos resultados reales al número de punto flotante más cercano, que se llama "redondeo". Para cada número de coma flotante, hay un rango de números reales que se redondeará a ese flotante, y a veces es útil pensar que el flotante se identifica con ese rango de números reales.

Como hay un suministro finito de números de coma flotante, debe haber un flotador positivo más pequeño, y su opuesto, el flotador negativo (magnitud) más pequeño. ¿Pero qué sucede con los resultados de números reales incluso más pequeños que esos ? Bueno, deben "redondear a cero". Pero "un número realmente pequeño mayor que cero" y "un número realmente pequeño menor que cero" son cosas muy diferentes con un comportamiento matemático muy diferente, entonces, ¿por qué deberíamos perder la distinción entre ellos, simplemente porque estamos redondeando? No tenemos que hacerlo

Entonces, el flotador 0 no solo incluye el número real 0, sino que también incluye cantidades positivas demasiado pequeñas para representar. Y el flotador -0 incluye cantidades negativas demasiado pequeñas para representar. Cuando los usa en aritmética, siguen reglas como "tiempos negativos positivos es igual a negativo; tiempos negativos negativo es igual a positivo". Aunque hemos olvidado casi todo acerca de estos números en el proceso de redondeo, todavía no hemos olvidado su signo.


No es una característica de Ruby, sino la parte de la especificación de número de coma flotante. Ver esta respuesta . El cero negativo es igual a cero positivo:

-0.0 == 0.0 # => true


Un ejemplo de cuándo podría necesitar -0.0 es cuando trabaja con una función, como tangente, secante o cosecante, que tiene polos verticales que deben ir en la dirección correcta. Puede terminar dividiendo para obtener un infinito negativo, y no querrá graficar eso como una línea vertical disparando hasta el infinito positivo. O es posible que necesite el signo correcto de una función que se aproxima asintóticamente a 0 desde abajo, como si tuviera una disminución exponencial de un número negativo y verifique que siga siendo negativo.