2016-08-15 33 views
5

Her zaman yüksek bir ondalık kesinlike ihtiyacımız var, hesaplamaları yapmak için ondalık kullanırız. Hassasiyetin hesaplama için yeterli olup olmadığını kontrol etmek için herhangi bir yolu var mı? Aşağıdaki kodu yapmak istiyorumHatalı hesaplamada nasıl bir istisna elde edilir?

bir istisna:

decimal almostMax = Decimal.MaxValue - 1; 
decimal x = almostMax + 0.1m; // This should create an exception, since x equals almostMax. 
Assert.AreEqual(x, almostMax); // This does NOT fail. 

Gerçekten gerçek kodda önemli değil, ama güvenli olması güzel olurdu.

+0

Ondalıkların sayısı 28 basamağa sahiptir (bazıları değil, hepsi de 29 basamağa sahip olabilir). Decimal.MaxValue, 28 basamaklı bir sayı olduğu için 0.1m ekleyerek ondalığın kesinliğini aşmaktadır, bu nedenle iki değer eşittir ve Assert başarısız olmaz. – PaulF

+2

@PaulF, Bence OP bunun farkında. Çalışma zamanı boyunca bu problemi tespit etmenin bir yolunu arıyor. –

+0

Lütfen bir istisnanın ağır bir operasyon olduğunu ve sadece gerçekleşmemesi gereken şeyler için kullanıldığını unutmayın. Bazı hesaplamaların başarısız olması olasıysa, bunun yerine "TryParse" gibi bir desen kullanmalısınız; bu, atma yerine boolean döndüren ve çok daha hızlı olacaktır. – Lukos

cevap

3

bir SaveDecimal sınıfını yapmak ve aşılmasına neden olabilir. İşlemi tersine çevirir ve giriş argümanlarının sonuçtan doğru şekilde hesaplanıp ayarlanamayacağını kontrol eder. Durum böyle değilse, operasyon hassas kayıplara neden oldu.

Çalışma örneği: https://dotnetfiddle.net/vx6UYY

vb + gibi düzenli operatörlerini kullanmak istiyorsanız, Philipp Schmid's solution ile gidip kendi ondalık türüne operatörleri uygulamak zorunda.

+1

Dikkat et, sonucun doğru olup olmadığını kontrol etmiyor. '11m' eklemeye çalışırken, '10m' yerine eklenirse, bu yöntem bir istisna atar. '(sonuç - a! = b || sonuç - b! = a)', herhangi bir özel duruma bakmıyorsam, bunu kapsamalıdır. – hvd

+0

@ hvd, iyi nokta! Onardım. –

+0

Performans etkisini makul bir seviyede tutabilen hoş bir özellik. – Andreas

0

+ 'da operatöre Bu uzantı yöntemi yardımcı olmalıdır
https://msdn.microsoft.com/en-us/library/aa288467%28v=vs.71%29.aspx

public class SafeDecimal 
{ 
    private decimal DecValue; 

    public SafeDecimal(decimal Value) 
    { 
     DecValue = Value; 
    } 

    public decimal GetValue() 
    { 
     return DecValue; 
    } 

    public static SafeDecimal operator +(SafeDecimal A, SafeDecimal B) 
    { 
     decimal almostMax = Decimal.MaxValue - 1; 

     checked 
     { 
      if (almostMax <= A.GetValue() + B.GetValue()) 
       throw new Exception("----scary error message----"); 
     } 

     return new SafeDecimal(A.GetValue() + B.GetValue()); 
    } 
} 
+1

Negatif değerleri hesaba katıyor mu? – zerkms

+0

Hayır, değil. Bunu düzeltmeliyim, teşekkürler. –

+1

C#, halihazırda aritmetik işlemler için taşma koruması sunmaktadır (bkz. Bu örnek: http://csharppad.com/gist/7f4edd08bde1061201ca13dca9332806). Zaten orada olan bir şeyi yeniden uyguladınız, ayrıca soru, hassas kayıpların taşmasıyla ilgili değildi. Ancak çözümün genel fikri iyi görünüyor. Sadece kodu değiştirin, böylece '+' OP tarafından belirtilen koşullar altında bir istisna atar ve bu cevap iyi IMO'dur. –