Math.Round ve MathF.Round doğru yuvarlanmış sonuçlar döndür

Math.Round(Double, Int32) ve MathF.Round(Single, Int32)ve aşırı MidpointRounding yüklemeleri artık girişin tam değerine göre istenen kesirli basamak sayısına doğru yuvarlanmış değeri döndürür. Bazı girişler artık önceki sürümlerden farklı (ve doğru) sonuçlara yuvarlanıyor. Buna ek olarak, bağımsız değişkenin digits artık üst sınırı yoktur.

Sürüm kullanıma sunulmuştur

.NET 11 Önizleme 7

Önceki davranış

Math.Round(value, digits, mode) Daha önce hesaplanmıştıRound(value * 10^digits, mode) / 10^digits. value * 10^digits Genel olarak tam olarak temsil edilemediği için, ondalık bir orta noktanın biraz altında (veya üstünde) değerler tam bir orta noktaya veya yuvarlama sınırına ölçeklendirilebilir ve bu da yanlış yuvarlanmış bir sonuç üretir. Büyük büyüklüğe sahip değerler de ölçeklendirme adımı sırasında kesirli bitlerini tamamen kaybedebilir.

Bağımsız digits değişken de için 0-15 double ve için 0-6 floatile sınırlıydı; bu aralığın dışındaki değerler attı ArgumentOutOfRangeException.

Math.Round(655.925, 2, MidpointRounding.AwayFromZero);            // 655.93              (incorrect)
Math.Round(1111111111111111.5, 1, MidpointRounding.AwayFromZero); // 1111111111111111.6  (incorrect)
Math.Round(1.5, 16, MidpointRounding.ToEven);                     // throws ArgumentOutOfRangeException

Örneğin, 655.925 olarak depolanır 655.924999999999954525…ve orta noktanın 655.925 altındadır, dolayısıyla doğru sonuç olur 655.92.

Yeni davranış

.NET 11'den başlayarak, sonuç rastgele duyarlık aritmetiği kullanılarak girişin tam değerinden hesaplanır ve döndürülen değer doğru yuvarlanmış ondalık sonuca en yakın temsil edilebilir değerdir.

Ayrıca, negatif digits olmayan herhangi bir değer kabul edilir; yalnızca negatif değerler oluşturur ArgumentOutOfRangeException. Sayı sayısı türüne gidiş dönüş yapmak için gereken duyarlığı (için double17, için float9) değeri değişmeden bırakır ve bu da doğru sonuç olur.

Math.Round(655.925, 2, MidpointRounding.AwayFromZero);            // 655.92              (correct)
Math.Round(1111111111111111.5, 1, MidpointRounding.AwayFromZero); // 1111111111111111.5  (correct)
Math.Round(1.5, 16, MidpointRounding.ToEven);                     // 1.5                 (no longer throws)

Kesinti yaratan değişiklik türü

Bu değişiklik davranışsal bir değişikliktir.

Değişiklik nedeni

Önceki sonuçlar büyük bir giriş kesirinde yanlıştı; desteklenen digits aralıktaki rastgele değerlerin kabaca 5% doğru yuvarlanmış sonuçtan farklıydı. Önceki davranış, büyük sonlu girişleri de reddetti veya yanlış işledi. Yeni uygulama IEEE tutarlıdır: girişin tam değerini yuvarlar ve daha önce üretilen değerle value.ToString("F{digits}") eşleşen en yakın temsil edilebilir sonucu döndürür.

0-15 ve 0-6 digits caps, eski ölçek-ölçütü10^digits yaklaşımına bağlı yapay bir sınırlamaydı. Tam uygulama herhangi bir basamak sayısı için doğru olduğundan, daha sonra ikinci bir davranışsal kesme önlemek için cap aynı anda kaldırıldı.

Daha fazla bilgi için bkz. dotnet/runtime#130574.

Çoğu kodun hiçbir değişikliğe ihtiyacı yoktur ve düzeltilen sonuçlardan yararlanır.

Tam olarak önceki (yanlış) çıkışa bağımlıysanız, önceki yaklaşımı açıkça kullanarak yuvarlar, örneğin. Math.Round(value * pow10, mode) / pow10 Alternatif olarak, değerler para birimi gibi temel 10 miktarları temsil ettiğinde kullanarak decimal yuvarlama gerçekleştirin.

double ve float ikili kayan nokta türleridir ve ondalık kesirlerin çoğunu tam olarak temsil etmemektedir. Ondalık miktarların tam ondalık yuvarlama için tercih edin Decimal. <System.Numerics.Decimal32>, <System.Numerics.Decimal64> ve <System.Numerics.Decimal128> , genişletilmiş aralıklara ve işlevlere sahip IEEE 754 ondalık tabanlı türlerdir ve bu çalışma türü için de uygundur.

Etkilenen API'ler

Aynı düzeltilmiş davranış ve yükseltilmiş digits aralık, bu yöntemlere temsilci olarak atanan sayısal arabirim giriş noktaları üzerinden (örneğin, double.Round, float.Round, Half.Roundve NFloat.Round) akar. Math.Round(Decimal, Int32) ve tek bağımsız değişken Math.Round(Double) ve MathF.Round(Single) aşırı yüklemeler etkilenmez.