Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Math.Round(Double, Int32) e MathF.Round(Single, Int32), e i relativi MidpointRounding overload, restituiscono ora il valore arrotondato correttamente al numero richiesto di cifre frazionarie in base al valore esatto dell'input. Alcuni input ora arrotondano a un risultato diverso (e corretto) rispetto alle versioni precedenti. Inoltre, l'argomento digits non ha più un limite superiore.
Versione introdotta
.NET 11 Preview 7
Comportamento precedente
In precedenza, Math.Round(value, digits, mode) calcolato Round(value * 10^digits, mode) / 10^digits. Poiché value * 10^digits in genere non è esattamente rappresentabile, i valori leggermente inferiori (o superiori) a un punto intermedio decimale possono essere ridimensionati in un punto medio esatto o attraverso un limite di arrotondamento, che ha generato un risultato arrotondato in modo errato. I valori con grandi dimensioni potrebbero anche perdere completamente i bit frazionari durante il passaggio di ridimensionamento.
L'argomento digits è stato limitato anche a 0-15 per double e 0-6 per float; i valori al di fuori di tale intervallo hanno generato 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
Ad esempio, 655.925 viene archiviato come 655.924999999999954525…, che è al di sotto del 655.925 punto intermedio, quindi il risultato corretto è 655.92.
Nuovo comportamento
A partire da .NET 11, il risultato viene calcolato dal valore esatto dell'input usando aritmetica a precisione arbitraria e il valore restituito è il valore rappresentabile più vicino al risultato decimale arrotondato correttamente.
Inoltre, viene accettato qualsiasi valore non negativo digits ; solo i valori negativi generano ArgumentOutOfRangeException. I conteggi delle cifre in corrispondenza o oltre la precisione necessaria per il round trip del tipo (17 per double, 9 per float) lasciano invariato il valore, ovvero il risultato corretto.
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)
Tipo di cambiamento che interrompe la compatibilità
Questa modifica è una modifica funzionale.
Motivo della modifica
I risultati precedenti non sono corretti per una frazione di input di grandi dimensioni, ovvero circa 5% di valori casuali nell'intervallo supportato digits differiscono dal risultato arrotondato correttamente. Anche il comportamento precedente ha rifiutato o gestito erroneamente input finiti di grandi dimensioni. La nuova implementazione è coerente con IEEE: arrotonda il valore esatto dell'input e restituisce il risultato rappresentabile più vicino, che corrisponde al valore value.ToString("F{digits}") già prodotto.
Il limite 0-15 e 0-6 digits era un limite artificiale legato all'approccio precedente.10^digits Poiché l'implementazione esatta è corretta per qualsiasi numero di cifre, il limite è stato sollevato contemporaneamente per evitare una seconda interruzione comportamentale in un secondo momento.
Per altre informazioni, vedere dotnet/runtime#130574.
Azione consigliata
La maggior parte del codice non necessita di modifiche e vantaggi dai risultati corretti.
Se si dipende dall'output precedente (errato), arrotondamento usando l'approccio precedente in modo esplicito, Math.Round(value * pow10, mode) / pow10ad esempio . In alternativa, eseguire l'arrotondamento usando decimal quando i valori rappresentano quantità di base 10, ad esempio valuta.
double e float sono tipi a virgola mobile binari e non possono rappresentare esattamente la maggior parte delle frazioni decimali. Per l'arrotondamento decimale esatto delle quantità decimali, preferire Decimal.
<System.Numerics.Decimal32>, <System.Numerics.Decimal64> e <System.Numerics.Decimal128> sono tipi basati su decimali IEEE 754 con intervalli e funzionalità espansi e sono adatti anche per questo tipo di lavoro.
Le API interessate
- System.Math.Round(Double, Int32)
- System.Math.Round(Double, Int32, MidpointRounding)
- System.MathF.Round(Single, Int32)
- System.MathF.Round(Single, Int32, MidpointRounding)
Lo stesso comportamento corretto e il flusso dell'intervallo lifted digits attraverso i punti di ingresso dell'interfaccia numerica che delegano a questi metodi, ad esempio , Half.Rounddouble.Roundfloat.Round, e .NFloat.Round
Math.Round(Decimal, Int32) e gli overload a argomento Math.Round(Double) singolo e MathF.Round(Single) non sono interessati.