Over afronden

Ondertussen hebben we 3 verschillende manier gezien om getallen af te ronden, namelijk:

  • Met behulp van casting.
  • Met behulp van Math.Round .
  • Met behulp van Convert.ToX.

Ieder manier gaat de data op een andere manier behandelen in het afronden, iets wat we tot nu toe bewust even hebben genegeerd. Bij casting is het duidelijk, deze rondt dus eigenlijk naar beneden af (het zelfde als wanneer je de Math.Floor-methode zou gebruiken). De twee andere manieren hebben enkele venijnige kantjes die we hier even willen bespreken.

Addertjes bij afronden

Op het eerste zicht lijkt afronden met Math.Round en Convert.ToX gewoon te werken:

double d1 = 4.2;
double d2 = 4.8;
Console.WriteLine($"afgerond: {Math.Round(d1)} en {Math.Round(d2)} ");

Dit zal de getallen 4 en 5 op het scherm tonen, zoals verwacht.

Je kan via een extra parameters de afronden nog wat bijsturen en vertellen tot hoeveel cijfer na de komma dit moet gebeuren:

double d1 = 4.12343;
Console.WriteLine($"afgerond: {Math.Round(d1,1)} en {Math.Round(d1,4)} ");

Dit zal de getallen 4.1 en 4.1234 op het scherm tonen. Alles lijkt dus in orde.

Maar kijk wat er gebeurt wanneer we een getal afronden dat op de helft van een getal ligt:

double d1 = 4.5;
double d2 = 5.5;
Console.WriteLine($"afgerond: {Math.Round(d1)} en {Math.Round(d2)} ");

Je zou 5 en 6 (of 4 en 5) verwachten. Niets is minder waar! De output hiervan wordt 4 en 6?!

Bankers rounding

Zonder extra informatie zal Math.Round (en ook Convert.ToInt32) altijd afronden naar het dichtstbijzijnde even getal. Dit wordt ook wel bankers rounding genoemd. Dit is een techniek die gebruikt wordt om afrondingsfouten te minimaliseren. Dat is heel leuk en handig voor bankiers, maar voor ons als programmeurs is dit niet altijd even handig.

Gelukkig kunnen we dit gedrag aanpassen door een extra parameter mee te geven aan de Math.Round-methode. Deze parameter is een MidpointRounding-enum. Deze enum heeft meerdere mogelijkheden, maar de meest gebruikte zijn:

  • ToEven: Dit is de standaardwaarde en zal afronden naar het dichtstbijzijnde even getal. De zogenaamde Bankers rounding dus.
  • AwayFromZero: Dit zal afronden naar het dichtstbijzijnde getal, ongeacht of het even of oneven is.

De tweede methode is de versie die wij prefereren, omdat deze het meest voorspelbare resultaat geeft. Nemen we terug ons voorbeeld, maar nu met de extra parameter:

double d1 = 4.5;
double d2 = 5.5;
Console.WriteLine($"afgerond: {Math.Round(d1,MidpointRounding.AwayFromZero)} en {Math.Round(d2, MidpointRounding.AwayFromZero)} ");

Dan krijgen we 5 en 6 zoals we verwachten.

Als je op de koop toe nog eens wil afronden naar een bepaald aantal cijfers na de komma, dan kan je dit ook nog steeds doen:

double d1 = 4.12343;
Console.WriteLine($"afgerond: {Math.Round(d1,1,MidpointRounding.AwayFromZero )} en {Math.Round(d1,4,MidpointRounding.AwayFromZero)} ");