Round here

Ok. Getallen afronden. Heel makkelijk. Of toch… je hebt verschillende smaken. En instinkers.

De lompe methode is om (int)4.8 te doen. Of Convert.ToInt32(4.8).
Maar dat is geen afronding, da’s cast en convert. En… de eerste methode levert 4 op, de tweede 5 als resultaat!
Want (int) hakt gewoon de decimalen eraf, convert rond het netjes af… maar bij de 4,5 gaat ie wel naar beneden. En die .5 grens gaan we straks ook tegenkomen.

Hoe zit het dan met int.Parse en int.TryParse? Die zijn alleen interessant om een integer die in een string zit verpakt om te zetten, waarbij parse een FormatException opgooit als de string niet als getal wordt herkend, wat met de tryparse netter kan worden afgehandeld.

System.Math

Dan de afrondingen zoals ze wiskundig verantwoord zijn ingebouwd met System.Math:

  • Math.Floor. rond af naar beneden
  • Math.Ceiling, rond af naar boven
  • Math.Truncate, hakt de decimalen er af

Hier een mooi schemaatje van internet geleend

 

-3        -2        -1         0         1         2         3
 +--|------+---------+----|----+--|------+----|----+-------|-+
    a                     b       c           d            e

                       a=-2.7  b=-0.5  c=0.3  d=1.5  e=2.8
                       ======  ======  =====  =====  =====
Floor                    -3      -1      0      1      2
Ceiling                  -2       0      1      2      3
Truncate                 -2       0      0      1      2

En je hebt Math.Round, deze rond af naar de dichtbijzijnde waarde.
Maar let op… BIJ ROUND ZIT EEN INSTINKER!

Console.WriteLine(Math.Round(-3.5)); // = -4
Console.WriteLine(Math.Round(-2.5)); // = -2
Console.WriteLine(Math.Round(-1.5)); // = -2
Console.WriteLine(Math.Round(-0.5)); // = 0
Console.WriteLine(Math.Round(0.5)); // = 0
Console.WriteLine(Math.Round(1.5)); // = 2
Console.WriteLine(Math.Round(2.5)); // = 2
Console.WriteLine(Math.Round(3.5)); // = 4

Dat is raar!?!

Omdat de .5 exact tussen twee integers in zit, hebben ze de Banker’s Rounding toegepast. Het is in ieder geval een regel die consequent is: bij deze waarde rond je altijd af naar een even getal.

“Maar dat wil ik niet!”

Dan is er gelukkig de overload met MidpointRounding.AwayFromZero parameter i.p.v. de default MidpointRounding.ToEven:

Console.WriteLine(Math.Round(-3.5,MidpointRounding.AwayFromZero)); // = -4
Console.WriteLine(Math.Round(-2.5,MidpointRounding.AwayFromZero)); // = -3
Console.WriteLine(Math.Round(-1.5,MidpointRounding.AwayFromZero)); // = -2
Console.WriteLine(Math.Round(-0.5,MidpointRounding.AwayFromZero)); // = -1
Console.WriteLine(Math.Round(0.5,MidpointRounding.AwayFromZero)); // = 1
Console.WriteLine(Math.Round(1.5,MidpointRounding.AwayFromZero)); // = 2
Console.WriteLine(Math.Round(2.5,MidpointRounding.AwayFromZero)); // = 3
Console.WriteLine(Math.Round(3.5,MidpointRounding.AwayFromZero)); // = 4

https://stackoverflow.com/questions/977796/why-does-math-round2-5-return-2-instead-of-3

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s