Inicialmente pensé que Math.Sign
sería la manera correcta de hacerlo, pero después de ejecutar una prueba parece que trata a -0.0
y +0.0
de la misma manera.¿Cómo puedo probar el cero negativo?
Respuesta
Aquí está una manera horrible truco de hacerlo:
private static readonly long NegativeZeroBits =
BitConverter.DoubleToInt64Bits(-0.0);
public static bool IsNegativeZero(double x)
{
return BitConverter.DoubleToInt64Bits(x) == NegativeZeroBits;
}
Básicamente esa es la prueba para el patrón de bits exacta de -0.0, pero sin tener que codificar la misma.
Parece que su solución es aproximadamente 25 veces más rápida que la mía. – ChaosPandion
Como bono adicional, sin gastos adicionales :) A veces tiene que amar el poder del código "inseguro" :) – leppie
@leppie - Ahora esto es increíble: 'return * (((long *) & value));' – ChaosPandion
Después de un poco de búsqueda finalmente llegué al Section 7.7.2 de la especificación C# y se me ocurrió esta solución.
private static bool IsNegativeZero(double x)
{
return x == 0.0 && double.IsNegativeInfinity(1.0/x);
}
Mientras aplaudo el ingenio, no estoy seguro de que sea el enfoque más * legible :) –
En realidad, -1 - cree que -double.Epsilon es cero negativo también ... –
@Jon - Dag nabbit – ChaosPandion
El cero negativo tiene el bit de signo configurado. Por lo tanto:
public static bool IsNegativeZero(double value) {
if (value != 0) return false;
int index = BitConverter.IsLittleEndian ? 7 : 0;
return BitConverter.GetBytes(value)[index] == 0x80;
}
Editar: como lo señaló OP, esto no funciona en el modo de lanzamiento. El optimizador x86 JIT toma en serio la sentencia if() y carga cero directamente en lugar de cargar el valor . Que de hecho es más eficiente. Pero eso hace que se pierda el cero negativo. El código debe ser de-sintonizado para evitar esto:
public static bool IsNegativeZero(double value) {
int index = BitConverter.IsLittleEndian ? 7 : 0;
if (BitConverter.GetBytes(value)[index] != 0x80) return false;
return value == 0;
}
Este comportamiento es bastante típica de la fluctuación de fase 86 por cierto, que no se ocupa de casos de esquina muy bien cuando se optimiza el código de punto flotante. El jitter x64 es mucho mejor en ese sentido. Aunque podría decirse que no hay peor caso de esquina que darle significado al cero negativo. Ser prevenido
Por alguna razón, cuando construyo esto con un objetivo de x86 con optimizaciones habilitadas y lo ejecuto fuera de Visual Studio, pasar '-0.0' devolverá' false'. Oh, y este parece ser el punto medio en cuanto a rendimiento. – ChaosPandion
I repro, la instrucción if confunde el optimizador JIT. Ahora asume que el valor es igual a cero, cero negativo y lo carga directamente con fldz en lugar de cargar * valor *. Porque eso es más rápido. También lucharás contra esto en tu propio código. Publicación actualizada –
Lamentablemente, para implementar completamente el estándar ECMAScript, debo tener en cuenta '-0.0'. – ChaosPandion
Aquí hay otro truco. Se aprovecha del hecho de que Equals
en un struct
va a hacer una comparación bit a bit en lugar de llamar Equals
de sus miembros:
struct Negative0
{
double val;
public static bool Equals(double d)
{
return new Negative0 { val = -0d }.Equals(new Negative0 { val = d });
}
}
Negative0.Equals(0); // false
Negative0.Equals(-0.0); // true
'ValueType.Equals' no siempre realiza una comparación bit a bit. Y, desafortunadamente, las condiciones exactas cuando elige hacerlo no están documentadas, y pueden variar entre las versiones/plataformas de CLR. –
x == 0 && 1/x < 0
De manera más general, se puede hacer,
bool IsNegative(double value)
{
const ulong SignBit = 0x8000000000000000;
return ((ulong)BitConverter.DoubleToInt64Bits(value) & SignBit) == SignBit;
}
o, alternativamente, si lo prefiere,
[StructLayout(LayoutKind.Explicit)]
private struct DoubleULong
{
[FieldOffset(0)]
public double Double;
[FieldOffset(0)]
public readonly ulong ULong;
}
bool IsNegative(double value)
{
var du = new DoubleULong { Double = value };
return ((du.ULong >> 62) & 2) == 2;
}
La tarde da una mejora a un rendimiento del 50% aproximado en depuración, pero. Una vez compilado en modo de lanzamiento y ejecutado desde la línea de comando , no hay una diferencia significativa.
No pude generar una mejora en el rendimiento utilizando un código inseguro tampoco, pero esto puede deberse a mi inexperiencia.
- 1. jstl cero negativo
- 2. ¿Cómo puedo eliminar de manera eficiente el flotante cero negativo de Ruby?
- 3. convertir el valor negativo a cero en mysql
- 4. ¿Utiliza el valor negativo de coma flotante cero?
- 5. ¿Cómo tener cero negativo siempre formateado como cero positivo en una cadena de python?
- 6. Signo negativo en caso de cero en java
- 7. ¿Cómo puedo probar ModelState?
- 8. ¿Cómo puedo probar el efftect de inclinación? - Simulador de iPhone
- 9. WP 7.5 - ¿Cómo puedo probar el tombstoning?
- 10. ¿Cómo se puede probar Get-ChildItem sin resultados (cero archivos)?
- 11. ¿Cómo ordenar una matriz de enteros en negativo, cero, parte positiva sin cambiar la posición relativa?
- 12. ¿Cómo puedo mostrar un símbolo negativo en .NET?
- 13. ¿Cómo puedo probar mi aplicación Dock
- 14. Postfix su instalado pero ¿cómo puedo probar
- 15. ¿Cómo puedo probar programáticamente las cookies?
- 16. ¿Cómo puedo probar la membresía de Asp.net?
- 17. ¿Cómo puedo probar Xcode Project en iPhone?
- 18. ¿Cómo puedo probar mis aplicaciones de iOS
- 19. ¿Cómo puedo probar rutas basadas en el subdominio Symfony2
- 20. ¿Cómo puedo probar el tipo de consulta que generará Mongoid?
- 21. ¿Cómo puedo probar el envío de un formulario en Jasmine?
- 22. ¿Cómo puedo probar el JavaScript potencialmente "bloqueador del navegador"?
- 23. ¿Cómo puedo probar el código jdbc en java?
- 24. C# DataTable ItemArray devuelve '{}': ¿cómo puedo probar el valor nulo?
- 25. ¿Cómo puedo probar el código que nunca se debe ejecutar?
- 26. ¿Cómo puedo probar el código del socket con PHPUnit?
- 27. En cmake, ¿cómo puedo probar si el compilador es Clang?
- 28. ¿Cómo puedo probar si el dispositivo IOS tiene capacidades telefónicas?
- 29. ¿Cómo puedo probar métodos privados con DUnit?
- 30. ¿Cómo puedo probar CanCan en la consola?
¿Qué es * cero negativo * y cómo es diferente a * cero positivo * y cómo es diferente de * cero *? Matemáticamente, son lo mismo. * IEEE 754ically * tal vez no. –
Bit a nivel, ¿cómo difiere la representación de -0.0 de +0.0? 0x800000 y 0x000000? – Davidann
@Darin Dimitrov, ¿alguna vez asistió a un curso de análisis matemático? : P –