I ran into the old familiar rounding issue - again. And of course, I didn't have the code I used to get it squared away.

My original blog post from 7 years ago, "Rounding the Currency type like they taught us in school", explains the issue in full detail and nothing has changed with regard to how Delphi handles rounding.

##
*And as usual David Heffernan gave...*

So I wen back to the Stack Overflow post to revisit the answers given to my original question. And as usual David Heffernan gave a very straightforward and succinct answer.

{---------------------------------------------------------------} { Added 2019-08-07 } { } { Used to solve the Delphi's rounding function. } { } { https://stackoverflow.com/q/10965759/195983 } { https://stackoverflow.com/a/10970283/195983 } {---------------------------------------------------------------} Function RoundTo2dp (Value: Currency): Currency; begin Result := Trunc(Value*100+IfThen(Value>0, 0.5, -0.5))/100; end;

I added the code to my StrStuff unit. (Does everyone have a StrStuff unit or is it just me?) And it did not compile. So, when I got done cussing out Heffernan for putting bum code out there, I did some digging.

It turns out there are two

**IfThen**functions. One in the

**SystemStrUtils**unit and the other one in the

**System.Math**unit. And of course, I chose the wrong unit.

##
*This specific IfThen function is from System.Math*

This specific

**IfThen**function is from the

**System.Math**unit:

unit Strstuff; interface uses System.Sysutils, System.Math; Function RoundTo2dp (Value: Currency): Currency;And of course after I put the correct unit in the uses clause it worked like a champ. I must admit, it felt good cussing out Heffernan. But as usual... he's right. Again!

Thank you David.

Enjoy!

Semper Fi

Gunny Mike

https://zilchworks.com

Using implicit order of uses statements is clever, but error-prone.

ReplyDeleteI encourage you to help yourself and others understand your code and avoid errors in the future by explicitly naming the source unit, like this:

Result := Trunc(Value*100 + SYSTEM.MATH.IfThen(Value>0, 0.5, -0.5))/100;

Thank you for pointing that out Tom.

DeleteIfThen is overloaded, so no need for a ordered uses list or full qualified calls of the function in this case!

DeleteThere are even more overloaded ifthen functions in various units.

ReplyDeleteAs for a Strstuff unit: I started off with a twmStringUtils unit, but over the more than 20 years it evolved into quite a long unit, so I subdivided it into several units.

It also works with System.Math.SimpleRoundTo

ReplyDeleteYou might wish to take a look at John Herbster's rounding routines:

ReplyDeletehttps://cc.embarcadero.com/Item/21909

They offer nearly any type of rounding you might want, e.g.:

drNone, {No rounding.}

drHalfEven,{Round to nearest or to even whole number. (a.k.a Bankers) }

drHalfPos, {Round to nearest or toward positive.}

drHalfNeg, {Round to nearest or toward negative.}

drHalfDown,{Round to nearest or toward zero.}

drHalfUp, {Round to nearest or away from zero.}

drRndNeg, {Round toward negative. (a.k.a. Floor) }

drRndPos, {Round toward positive. (a.k.a. Ceil ) }

drRndDown, {Round toward zero. (a.k.a. Trunc) }

drRndUp); {Round away from zero.}

He also wrote a great paper on the ins and outs of rounding, but I cannot find the link right now.