.NET neden banker yuvarlamasını varsayılan olarak kullanıyor?


271

Dokümantasyona göre, decimal.Roundyöntem çoğu uygulama için yaygın olmayan bir yuvarlama algoritması kullanır. Bu yüzden her zaman daha doğal yuvarlak yarım yukarı algoritma yapmak için özel bir işlev yazıyorum:

public static decimal RoundHalfUp(this decimal d, int decimals)
{
    if (decimals < 0)
    {
        throw new ArgumentException("The decimals must be non-negative", 
            "decimals");
    }

    decimal multiplier = (decimal)Math.Pow(10, decimals);
    decimal number = d * multiplier;

    if (decimal.Truncate(number) < number)
    {
        number += 0.5m;
    }
    return decimal.Round(number) / multiplier;
}

Bu çerçeve tasarımı kararının ardındaki nedeni bilen var mı?

Yuvarlama yarım algoritmanın çerçeveye yerleşik bir uygulaması var mı? Veya yönetilmeyen bir Windows API'sı olabilir mi?

Yeni başlayanlar için decimal.Round(2.5m, 0)bir sonuç olarak 3 beklentisini yazıp bunun yerine 2 elde etmek yanıltıcı olabilir .


105
Yuvarlama "daha doğal" değildir. Doğanın onunla hiçbir ilgisi yoktur. “Yuvarlama” kavramını öğrendiğinizde, okulda öğrendikleriniz budur. Sınıf dersleri her zaman tam bir resim çizmez.
Rob Kennedy

45
@Rob Ve bu yüzden doğru olmasa bile , daha doğal
Pacerier

10
Anlamıyorum @ Pacerier. O yüzden ben izah değil doğal ve bunu neden aslında söylemek olduğunu doğal. Benim argümanım seninkinin tersi olan sonucuma karşı nasıl çalışır ? Alıştığınız şeyler doğal hissedebilir ve bazen mecazi olarak bir şeyin "ikinci doğa" olduğunu söyleriz, ama bu onları doğal yapmaz.
Rob Kennedy

16
@ Doğal diyorum, çünkü doğal geliyor. Doğal olarak aynı değişken adına sahip 36 farklı nesne olduğunu biliyor musunuz ?
Pacerier

9
doğanın açık bir şekilde analogu yani yanlış kelime; ama bu bilgiçlik taslayan. Belki kullanım için daha iyi bir kelime 'olağan' olurdu .. "insanların yaptığı o zamanki yuvarlama ne"> 0.5 1.0 gider
whytheq

Yanıtlar:


196

Muhtemelen daha iyi bir algoritma olduğu için. Gerçekleştirilen birçok yuvarlama boyunca, tüm .5'lerin eşit olarak yukarı ve aşağı yuvarlandığını ortalama olarak göreceksiniz. Bu, örneğin bir grup yuvarlatılmış sayı ekliyorsanız, gerçek sonuçlara ilişkin daha iyi tahminler verir. Bazılarının beklediği şey olmasa da, muhtemelen daha doğru bir şey olduğunu söyleyebilirim.


71
Tabii ki tek ve çift girdilerin düz bir dağılımına sahip olduğunuzu varsayarsak
jk.

7
Daha iyi algoritma için +1 , ancak Ostemar gerçek cevaba sahip olsa da ( stackoverflow.com/questions/311696/… )
Ian Boyd

2
@Ian, bu yanıtı + 1'ledim. Neyse biz "kabul edilen cevap taşındı" Belki OP bunu yapabilir. Bu yöntemi "neden" kullanmasının asıl cevabı sayfanın yarısı kadar. Temsilciyi arttırmayı sevmeme rağmen, bu cevaptan haftada bir kez alıyorum.
Kibbee

@Kibbee - cevabımı ittiğin için teşekkürler. Uygun gördüğü gibi kabul edilen cevabı değiştirmek OP için mi sanırım?
Ostemar

-1 daha iyi bir algoritma olduğunu belirtmek için. - Bankanın yuvarlamasını kullanarak rastgele bir sayı örneği verildiğinde, tek konumlarda tek konumlardan daha fazla sayı elde edersiniz. - Sadece bu rakamları ortalamanızdan sonra, orijinal dağılıma tekrar benzer bir dağılım elde edersiniz. - Örneğin, bu verileri bir dağılım grafiğinde çizerseniz, yapay gruplama görülebilir.
paul23

437

Bankanın algoritmasının (diğer bir deyişle yarı yarıya ) iyi bir seçim olmasının nedenlerine dair diğer cevaplar oldukça doğrudur. Çoğu makul dağılımda sıfır yönteminden yuvarlak yarıya kadar negatif veya pozitif yanlılıktan muzdarip değildir .

Ancak soru, .NET'in neden Banker'ın gerçek yuvarlamasını varsayılan olarak kullanmasıydı ve cevap, Microsoft'un IEEE 754 standardını izlemesidir . Bu aynı zamanda Matematik için MSDN'de de belirtilmiştir .

Ayrıca .NET'in MidpointRoundingnumaralandırma sağlayarak IEEE tarafından belirtilen alternatif yöntemi desteklediğini unutmayın . Elbette bağları çözmek için daha fazla alternatif sunmuş olabilirler, ancak sadece IEEE standardını yerine getirmeyi seçerler.


17
Peki, IEEE 754 neden bankacıları takip ediyor? Bu (hala iyi) cevap sadece kovadan geçer.
Henk Holterman

4
@HenkHolterman Muhtemelen diğer cevaplarda bahsedilenlerden (ve özetlediğim gibi); negatif veya pozitif yanlılıktan (çok fazla) muzdarip değildir ve bu nedenle çoğu dağıtım ve problem alanı için daha resonable bir varsayılan yapar.
13'te Ostemar


İlginçtir, çünkü IEEE 754 Ondalık olmayan kayan nokta sayıları için standarttır. Belki de IEEE 754'ü izler, böylece Decimal olarak Double'u yuvarlamak için aynı algoritma kullanılır.
Brandon Barkley

1
@BrandonBarkley Bir Ondalık veya ondalık olan bir kayan nokta sayısı ve IEEE 754 içermez ondalık kayan nokta sayıları.
Pablo H

88

"Microsoft tasarımcıları bunu neden varsayılan olarak seçti?" Sorusuna cevap veremesem de, fazladan bir işlevin gereksiz olduğunu belirtmek istiyorum.

Math.Roundaşağıdakileri belirlemenizi sağlar MidpointRounding:

  • ToEven - Bir sayı diğer ikisinin arasında olduğunda, en yakın çift sayıya yuvarlanır.
  • AwayFromZero - Bir sayı diğer ikisi arasında yarım olduğunda, sıfırdan uzakta en yakın sayıya yuvarlanır.

8
Ve ilgili iş parçacıklarında bahsettiğim gibi, yuvarlamada tutarlı olduğunuzdan emin olun - bazen veritabanında yuvarlama yaparsanız ve bazen .net'de, haftalarca tutacak garip, bir kuruş hatalarınız olur çözmek.
chris

59
Bir müşteri bir keresinde bana 40.000 dolardan fazla para ödedi, ikisi de sadece 1 MİLYAR dolarlık utangaç olan iki sayı arasındaki 0,1 dolarlık bir yuvarlama hatasını izledi; 0.11 $ bir anabilgisayar ve SQL Server arasındaki 8. basamak yuvarlama hata farkı nedeniyle oldu. Mükemmeliyetçi hakkında konuşun!
EJ Brennan

12
@EJB - Ben bir milyar dolar ile uğraşıyor olsaydım muhtemelen bir mükemmeliyetçi olurdu ;-)
royse41

12
@EJ Brennan: Bunu anlamanız 40 bin dolar mı aldı? Her zaman böyle problemler görüyorum, yuvarlama # 1, çift / şamandıra normalizasyonu # 2, programcı hatası # 3 - # 3 önceden tanımlanmış test örnekleri yoksa hemen # 1 olarak ayarlanabilir. btw lütfen bana milyarder müşterinizle temas kurabilir misiniz, ben de onun sisteminde birkaç tane daha $ 40k hata bulabilirim düşünüyorum! : D

3
@seanxe: Veya Office Space'i görseydiniz. Cidden, paradaki gizemli, küçük yanlışlıkları her gördüğünüzde, tam olarak nasıl olduklarının gizemini çözmek neredeyse her zaman iyi bir fikirdir. Hataları düzeltmemeye karar vermeniz mümkündür, ancak altta yatan nedenin bilinmesi hala değerlidir. Bahse girerim para ile çalışan birçok insan küçük yanlışlıkları bile fark etmekten mutluluk duyar.
Brian

22

Ondalık sayılar çoğunlukla para için kullanılır ; bankacının yuvarlaması para ile çalışırken yaygındır . Ya da söyleyebilirsin.

Çoğunlukla ondalık tipe ihtiyaç duyan bankacılardır; bu nedenle “bankacının yuvarlanması”

Yuvarlanan bankacılar, aşağıdaki durumlarda ortalama olarak aynı sonucu elde etmeniz avantajına sahiptir:

  • eklemeden önce bir dizi "fatura satırı" yuvarlayın,
  • veya ekleyin ve ardından toplamı tamamlayın

Toplamadan önce yuvarlama, bilgisayarlardan önceki günlerde çok fazla iş tasarrufu sağladı.

(İngiltere'de ondalık bankalara gittiğimizde yarım peni ele almazdı, ama uzun yıllar hala hala yarım peni bozuk para vardı ve dükkanın fiyatları genellikle yarım peni ile bitiyordu - çok fazla yuvarlama)


8
"Ondalıklar çoğunlukla para için kullanılır" ... ve tamsayı olmayan her şey.
John Tyree

3
@JohnTyree, Çoğu zaman bir tamsayı olmadığında bir double / float kullanılır. bkz. stackoverflow.com/questions/2545567/…
Ian Ringrose

3
Vay. Benim açımdan saçma hata. Decmials, evet. Ondalık sayılar, hayır. Gelecek nesiller için, buradaki orijinal düşünceye katılıyorum.
John Tyree

Bankacılar bankacıların yuvarlanmasını sevebilir, ancak muhasebeciler onun hayranı olmayabilir, 0.005 farkının tek veya çift sayıya bağlı olarak değil, 0,01 kadar yuvarlanması gerektiğini söylüyorlar.
JustAMartin

0

Round fonksiyonunun başka bir aşırı yükünü kullanın:

decimal.Round(2.5m, 0,MidpointRounding.AwayFromZero)

Çıkış 3 olacaktır . Ve eğer kullanırsan

decimal.Round(2.5m, 0,MidpointRounding.ToEven)

bankacının yuvarlanmasını alacaksınız.


4
Bu, Bankanın Yuvarlamasının neden varsayılan olarak seçildiği sorusuna cevap vermiyor .
shortstuffsushi
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.