Domanda

Ho fatto alcune prove con calcoli in virgola mobile per ridurre al minimo la perdita di precisione. Mi sono imbattuto in un fenomeno che voglio mostrare qui e si spera ottenere una spiegazione.

Quando scrivo

print 1.0 / (1.0 / 60.0)

il risultato è

60.0024000960

Quando scrivo la stessa formula e fare cast esplicito a float

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

il risultato è

60

Fino ad ora ho pensato che letterali numerici con decimali vengono trattati automaticamente come real valori con la precisione adeguata. Trasmissione a <=> mostra lo stesso risultato di colata a <=>.

  • C'è qualche documentazione su come SQL Server valuta costanti numeriche?
  • A che tipo di dati sono quelle letterali?
  • Devo davvero di gettare loro di <=> ottenere una migliore precisione (che suona come l'ironia per me:)?
  • C'è un modo più facile di ingombrare le mie formule con calchi?
È stato utile?

Soluzione

SQL Server utilizza il più piccolo tipo di dati possibile.

Quando si esegue questo 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')

vedrai che SQL Server implicitamente utilizzato un NUMERICO (2, 1) tipo di dati.
La divisione del 60,0 converte il risultato a numerico (8, 6).
Il calcolo finale converte il risultato a numerico (17, 10).


Modifica

Tratto da linea di SQL Server tipo di dati di conversione

  

In istruzioni Transact-SQL, una costante   con punto decimale è automaticamente   convertito in un valore dato numerico,   utilizzando la precisione e la scala minima   necessario. Ad esempio, la costante   12.345 viene convertito in un valore numerico con una precisione di 5 e   scala 3.

Altri suggerimenti

Si, si hanno spesso di gettare loro di galleggiare ottenere una migliore precisione. Il mio prendere su di esso:

Per una migliore precisione di lanciare decimali prima di calcoli

Penso che dovrebbe essere compreso che cosa sta succedendo dietro le quinte per riferimento futuro in casi analoghi.

i valori numerici letterali con punto decimale esclusi notazione scientifica rappresentano il tipo di dati decimale che viene memorizzato come il più piccolo tipo decimale possibile. Stessa citazione come Lieven Keersmaekers di da: https://msdn.microsoft.com/en -us / library / ms191530% 28SQL.90% 29.aspx # _decimal

  

In istruzioni SQL, una costante con un punto decimale è   automaticamente convertito in un valore dato numerico, utilizzando la minima   precisione e scala necessaria. Ad esempio, la costante è 12.345   convertito in un valore numerico con una precisione di 5 e una scala di 3.

Gli zeri finali a destra del punto decimale specificano scala. Gli zeri iniziali a sinistra del punto decimale vengono ignorate.

Alcuni esempi:

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

Un altro punto da considerare è Tipo di dati la precedenza . Quando un operatore combina due espressioni di diversi tipi di dati, le regole per il tipo di dati precedenza specificano che il tipo di dati con precedenza inferiore viene convertito nel tipo di dati con la priorità più alta. E ancora un altro punto da considerare è se facciamo operazioni aritmetiche sui tipi decimali che il tipo decimale risultante, cioè precisione e scala dipendono sia operandi e dell'operazione stessa. Questo è descritto nel documento Precisione, scala e lunghezza .

Quindi, una parte della vostra espressione tra parentesi

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

utilizzando sopra le regole circa precisione e la scala di espressioni decimali. Inoltre, il banco di arrotondamento o arrotondamento per addirittura viene utilizzato. È importante notare arrotondamento diverso vengono utilizzati decimale e tipo float. Se continuiamo l'espressione

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

Così la parte della differenza è dovuta alla differente arrotondamento utilizzato per i tipi decimali rispetto al flottante.

In accordo con le regole di cui sopra, sarebbe sufficiente utilizzare un solo getto dentro parentesi. Ogni altro letterale sarà promosso a galleggiare in conformità delle norme di precedenza tipo di dati.

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

E una cosa più importante. Anche questa espressione galleggiante non calcola risultato esatto. E 'solo così che l'estremità anteriore (SQL Server Management Studio o qualsiasi altra cosa) arrotonda il valore di (credo) precisione 6 cifre e poi tronca gli zeri finali. Quindi, vale a dire 1.000001 diventa 1.

Semplice, non è vero?

Per scrivere un'espressione galleggiante costante, tenta di utilizzare la notazione scientifica:

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

Il risultato è 60.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top