2009-07-02 17 views
9

Hassas kaybı en aza indirmek için kayan nokta hesaplamaları ile bazı testler yaptım. Burada göstermek istediğim bir fenomenle karşılaştım ve umarım bir açıklama olsun.SQL Server: Sayısal değişmezlerle hesaplama

ben de aynı formülü yazıp float

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

için açık döküm yapmak sonuç

olduğunda sonuç

60.0024000960 

olduğunu

print 1.0/(1.0/60.0) 

yazdığınızda


Şimdiye kadar ondalık basamaklı sayısal hazır otomatik olarak uygun hassasiyetle float değerler olarak kabul edilir olduğu düşünülmektedir. real'a döküm, float'a döküm ile aynı sonucu gösterir.

  • SQL Server'ın sayısal değişmezleri nasıl değerlendirdiği hakkında bazı belgeler var mı?
  • Bu veri türleri hangi veri türleridir?
  • float'u daha iyi bir hassasiyete atmak zorunda mıyım? (Bana ironi gibi geliyor) :)?
  • Formüllerimin kalıplarla karıştırılmasından daha kolay bir yol var mı?

cevap

9

SQL Server, mümkün olan en küçük veri türünü kullanır.

Eğer SQL Server örtülü bir SAYISAL (2, 1) veri türü kullanılır olduğunu göreceksiniz bu komut dosyasını

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') 

çalıştırmak

.
60.0 bölümü, sonucu NUMERIC (8, 6) olarak dönüştürür.
Son hesap, sonucu NUMERIC (17, 10) olarak dönüştürür. ondalık basamağa sahip bir sabit ,

Transact-SQL açıklamalarda

SQL Server Books Online Data Type Conversion Alındığı


Düzenleme

, otomatik bir sayısal verileri değerine dönüştürülür olduğunu , minimum hassasiyet ve ölçeğini kullanarak gerekli. Örneğin, sabit 12,345 sık daha iyi hassasiyet elde yüzer onları döküm zorunda 5 kişilik bir hassasiyet ve 3.

+0

Ah .. Şu ana kadar bu yöntemi bilmiyordum. Çok teşekkür ederim :) – VVS

+0

Öyleyse, beklenen sonucu elde etmek için açık bir oyuncu yok mu? SQL Server'a belirli bir değişmez türün (örn.) Yüzdürme olduğunu söylemenin başka bir yolu var mı? – VVS

+0

@VVS, zaten yaptığınız gibi açık bir dökümün yanı sıra bildiğim kadarıyla değil. SQL Server, her zaman değeri sayısal olarak yorumlar.Kendiniz 1,00000000000000000000000000000000000000 gibi değerlerinizi hassaslaştırırsanız, sorun biraz azaltılabilir. –

4

Evet bir ölçekli bir sayısal değere dönüştürülür.Üzerinde Benim alabilir:

For better precision cast decimals before calculations

+0

Makaledeki mantık hatalı. Bazı keyfi değerlere dayanmaktadır. Ondalık türü lehine ters örnek bulmak kolay olurdu. Bir ampirik örneğe dayanan bu Hint iddiaları, kendi içinde tuzaklardır. – f470071

3

Ben benzer durumlarda ileride başvurmak üzere perde arkasında neler olduğunu anlaşılmalıdır düşünüyorum.

Bilimsel gösterimi hariç ondalık basamaklı sayısal sayısal değerler, mümkün olan en küçük düzeyde saklanan ondalık veri türünü temsil eder Ondalık tipi. Transact-SQL açıklamalarda https://msdn.microsoft.com/en-us/library/ms191530%28SQL.90%29.aspx#_decimal

, ondalık basamağa sahip bir sabit otomatik asgari duyarlık ve ölçeği gerekli kullanarak, bir sayısal verileri değerine dönüştürülür: den Lieven Keersmaekers en aynısı alıntı. Örneğin sabit 12.345 5 bir hassasiyet ve ölçek belirtmek ondalık noktasının sağındaki 3.

sondaki sıfırlar bir ölçekte bir sayısal değer dönüştürülür. Ondalık noktasının solundaki sıfırlar göz ardı edilir.

Bazı örnekler:

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

başka nokta dikkate almak Data Type precedence olduğunu. Bir işleç, farklı veri türlerinin iki ifadesini birleştirdiğinde, veri türü önceliği kuralları, daha düşük önceliğe sahip veri türünün, daha yüksek önceliğe sahip veri türüne dönüştürüleceğini belirtir. Ve yine dikkate alınması gereken bir başka nokta ise, Ondalık türleri üzerinde elde edilen Ondalık tipi, yani doğruluk ve ölçek, hem işlenenlere hem de işlemin kendisine bağlı olarak aritmetik işlemler yaparsak yapılmasıdır. Bu, Precision, Scale, and Length numaralı belgede açıklanmıştır.

Yani, Hassas ve Ondalık ifadelerin ölçeği ilgili kuralları yukarıda kullanarak parantez

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

da ifade parçasıdır. Ayrıca bankanın yuvarlama veya yuvarlama bile kullanılır. Ondalık ve float tipi için farklı yuvarlamaların not edilmesi önemlidir. Biz ifadesini

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

devam ederse Yani tutarsızlık parçası şamandıra için daha ondalık türleri için kullanılan farklı yuvarlama kaynaklanmaktadır. Yukarıdaki kurallara uygun olarak, parantez içinde sadece bir dökümün kullanılması yeterli olacaktır. Diğer her türlü literal, Veri Türü Öncelik kurallarına uygun olarak yüzdürülebilir.

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

Ve bir tane daha ÖNEMLİ şey. Bu yüzdürme ifadesi bile kesin sonucu hesaplamaz. Öyle ki, ön uç (SSMS ya da her neyse), değeri 6 saniyelik bir doğrulukla (sanırım) yuvarlar ve daha sonra sıfırları keser. Yani, 1.000001, 1 olur.

Basit değil mi?