Pregunta

Lo hice algunas pruebas con los cálculos de punto flotante para minimizar la pérdida de precisión. Me encontré con un fenomeno que quiero mostrar aquí y es de esperar obtener una explicación.

Cuando escribo

print 1.0 / (1.0 / 60.0)

el resultado es

60.0024000960

Cuando escribo la misma fórmula y hacer una conversión explícita a float

print cast(1.0 as float) / (cast(1.0 as float) / cast(60.0 as float))

el resultado es

60

Hasta ahora yo pensaba que los literales numéricos con decimales se tratan automáticamente como real valores con la precisión adecuada. La conversión a <=> muestra el mismo resultado que la fundición a <=>.

  • ¿Hay algún tipo de documentación sobre cómo SQL Server evalúa los literales numéricos?
  • ¿De qué tipo de datos son los literales?
  • ¿Realmente tengo para echarlos a <=> obtener una mejor precisión (que suena como la ironía para mí:)?
  • ¿Hay una manera más fácil de confundir mis fórmulas con los moldes?
¿Fue útil?

Solución

SQL Server utiliza el tipo de datos más pequeño posible.

Al ejecutar este script

SELECT SQL_VARIANT_PROPERTY(1.0, 'BaseType')
SELECT SQL_VARIANT_PROPERTY(1.0, 'Precision')
SELECT SQL_VARIANT_PROPERTY(1.0, 'Scale')
SELECT SQL_VARIANT_PROPERTY(1.0, 'TotalBytes')

verá que SQL Server utiliza implícitamente un tipo de datos numéricos (1 2).
La división por 60,0 convierte el resultado a numérico (8, 6).
El cálculo final convierte el resultado a numérico (17, 10).


Editar

Tomado de SQL Server Books Online de conversión de datos Tipo

  

En instrucciones Transact-SQL, una constante   con un punto decimal es automáticamente   convertida en un valor de dato numérico,   utilizando la precisión y la escala mínima   necesario. Por ejemplo, la constante   12.345 se convierte en un valor numérico con una precisión de 5 y una   escala de 3.

Otros consejos

Sí, que con frecuencia tienen que echarlos a flotar obtener una mejor precisión. Mi opinión sobre ella:

Para una mejor precisión fundido decimales antes de cálculos

Creo que se debe entender lo que está pasando detrás de las escenas para referencia futura en casos similares.

Los valores numéricos literales con punto decimal representan excluyendo notación científica tipo de datos decimal que se almacena como mínimo de tipo decimal posible. Misma cita como Lieven Keersmaekers de entre: https://msdn.microsoft.com/en -us / biblioteca / ms191530% 28SQL.90% 29.aspx # _decimal

  

En instrucciones Transact-SQL, una constante con un punto decimal se   convertido automáticamente en un valor de dato numérico, utilizando el mínimo   la precisión y la escala necesaria. Por ejemplo, la constante de 12,345 es   convertida en un valor numérico con una precisión de 5 y una escala de 3.

Los ceros de la izquierda a la derecha del punto decimal especifican escala. Los ceros a la izquierda a la izquierda del punto decimal se ignoran.

Algunos ejemplos:

1.0  -> Decimal(2,1)
60.0 -> Decimal(3,1)
1.00 -> Decimal(3,2)
01.0 -> Decimal (2,1)

Otro punto a considerar es Tipo de datos precedencia . Cuando un operador combina dos expresiones de diferentes tipos de datos, las reglas para el tipo de datos precedencia especifican que el tipo de datos con la prioridad más baja se convierte en el tipo de datos con la prioridad más alta. Y otro punto a considerar es si hacemos operaciones aritméticas sobre tipos de decimales que el tipo decimal resultante, es decir, la precisión y la escala dependen de los dos operandos y operación en sí. Esto se describe en el documento Precisión, escala y longitud .

Por lo tanto, parte de su expresión entre paréntesis

( 1.0 / 60.0 ) is evaluated to 0.016666 and the resulting type is Decimal (8,6)

utilizando encima de las reglas sobre la precisión y la escala de las expresiones decimales. Además, el banquero de redondeo o redondeo a se utiliza incluso. Es importante tener en cuenta diferentes redondeo de decimales se utilizan y el tipo de flotador. Si seguimos la expresión

1.0 / 0.016666 is evaluated to 60.002400096 and the resulting type is Decimal (17,10)

Así que la parte de la discrepancia se debe a diferentes redondeo que se utiliza para este tipo de decimales que para el flotador.

De acuerdo con las reglas anteriores sería suficiente utilizar sólo un fundido dentro de paréntesis. se promoverá cada dos literales a flotar en conformidad con las reglas de precedencia de tipo de datos.

1.0 / (1.0 / cast(60.0 as float))

Y una cosa más importante. Incluso esta expresión de coma flotante no calcula resultado exacto. Es sólo para que el extremo delantero (SSMS o lo que sea) redondea el valor a (supongo) de precisión 6 dígitos y luego trunca ceros a la derecha. Así es decir, se convierte en 1.000001 1.

simple, ¿verdad?

Para escribir una expresión de flotación constante, trate de usar la notación científica:

select (1.0E0 / (1.0E0 / 60.0E0))

El resultado es 60.

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