Perché .NET utilizza l’arrotondamento del banchiere come predefinito?

Secondo la documentazione, il metodo decimal.Round utilizza un algoritmo round-to-even che non è comune per la maggior parte delle applicazioni. Quindi finisco sempre per scrivere una funzione personalizzata per fare l’algoritmo round-half-up più naturale:

 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; } 

Qualcuno conosce il motivo dietro questa decisione di progettazione di struttura?

Esiste una implementazione integrata dell’algoritmo round-half-up nel framework? O forse qualche API Windows non gestita?

Potrebbe essere fuorviante per i principianti che scrivono semplicemente decimal.Round(2.5m, 0) prevede 3 come risultato ma ottiene 2 invece.

Probabilmente perché è un algoritmo migliore. Nel corso di molti arrotondamenti eseguiti, otterrai una media di tutti i .5 che finiscono per arrotondare ugualmente su e giù. Ciò fornisce migliori stime dei risultati effettivi se ad esempio si aggiunge una serie di numeri arrotondati. Direi che anche se non è quello che ci si potrebbe aspettare, è probabilmente la cosa più corretta da fare.

L’altro risponde con i motivi per cui l’algoritmo del banchiere (anche noto come round half even ) è una buona scelta. Non soffre di bias negativi o positivi tanto quanto la metà tonda del metodo zero rispetto alla maggior parte delle distribuzioni ragionevoli.

Ma la domanda era: perché .NET utilizza l’arrotondamento effettivo di Banker come predefinito – e la risposta è che Microsoft ha seguito lo standard IEEE 754 . Ciò è anche menzionato in MSDN per Math.Round in Note.

Si noti inoltre che .NET supporta il metodo alternativo specificato da IEEE fornendo l’enumerazione MidpointRounding . Potrebbero naturalmente aver fornito più alternative alla soluzione dei legami, ma hanno scelto di soddisfare semplicemente lo standard IEEE.

Mentre non posso rispondere alla domanda “Perché i designer di Microsoft hanno scelto questo come predefinito?”, Voglio solo sottolineare che una funzione extra non è necessaria.

Math.Round consente di specificare un MidpointRounding :

  • ToEven – Quando un numero è a metà strada tra due altri, viene arrotondato al numero pari più vicino.
  • AwayFromZero – Quando un numero è a metà strada tra due altri, viene arrotondato al numero più vicino che è lontano da zero.

I decimali sono principalmente usati per soldi ; l’arrotondamento del banchiere è comune quando si lavora con denaro . O potresti dire.

Sono soprattutto i banchieri che hanno bisogno del tipo decimale; quindi fa “l’arrotondamento del banchiere”

Gli arrotondamenti bancari hanno il vantaggio che in media otterrai lo stesso risultato se:

  • arrotondare una serie di “righe di fatturazione” prima di aggiungerle,
  • o aggiungerli poi intorno al totale

L’arrotondamento prima di aggiungere ha salvato molto lavoro nei giorni precedenti ai computer.

(Nel Regno Unito, quando siamo diventati decimali, le banche non si sarebbero occupate di mezzo penny, ma per molti anni c’era ancora una moneta da mezzo penny e il negozio spesso aveva prezzi che finivano a mezzo penny – quindi molti arrotondamenti)

Usa un altro sovraccarico della funzione Round come questo:

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

Produrrà 3 . E se usi

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

Otterrai l’arrotondamento del banchiere.