Alaska Software Inc. - The Lost Penny
Username: Password:
AuthorTopic: The Lost Penny
Ernie BarlowThe Lost Penny
on Fri, 13 Mar 2009 10:31:38 +0000
Morning,

 Is this a bug, a "feature", or something I can do differently?.

 I was checking the result of a sales price calculation on a report when I
came across:

    ROUND(  ( 81.85  / 100 * 110 ) ,2 )    -  which gave 90.03.

 All three of my calculators said this should be 90.04. Additionally Clipper
5.3
 and the latest incarnation of FoxPro both gave the result as 90.04.

 Change the order of the operands to :

    ROUND(  ( 81.85  * 110 / 100 ) ,2 )   -  we now get 90.04

 Looking further, the result of the first expression is 90.034999999999990,
and the
 second is 90.035000000000000

 Sorry if this ground has been covered before but I don't come here very
often.
 I use Alaska 1.82.306


 Regards

 Ernie Barlow
Rodd Graham Re: The Lost Penny
on Fri, 13 Mar 2009 10:52:30 +0000
Hello Ernie,

> Is this a bug, a "feature",

Neither.  It is the nature of floating point representational error due to 
the mismatch between binary (base 2) and decimal (base 10).  All math libraries 
that utilize base 2 are subject to this problem.

> or something I can do differently?.

Yes.  Save your division to the end (which you did) OR update to v1.9 which 
I tested to return 90.04 (specific case) OR use integer math OR switch your 
applications number system from base 10 to base 2.

Regards,

Rodd Graham, Consultant
Graham Automation Systems, LLC
Ernie BarlowRe: The Lost Penny
on Fri, 13 Mar 2009 14:01:07 +0000
Thanks Rodd for a prompt response.

The bit I wanted to hear was that version 1.9 gave the correct result.

While I understand your comments re:  binary vs decimal,  surely we 
should'nt be concerned
nowadays about getting wrong answers when we multiply, divide, then round a 
few small
numbers?.

I thought, as a tempory measure, of using something like ROUND ( ROUND ( 
<Exp> , 8 ) , 2 ).
This works in my case, but seems a bit clumsy for general use.

Your comment about leaving divisions to the end is interesting. Does this 
allow the
floating point package to retain more intermediate accuracy? In any case I 
don't fancy
altering the order of operands in all my ROUND() functions, V1.9 seems the 
way to go.

Thanks again,
Ernie Barlow

"Rodd Graham" <rgraham@grahamautomation.com> wrote in message 
news:6c56a922499648cb71b7084a07ad@news.alaska-software.com...
> Hello Ernie,
>
>> Is this a bug, a "feature",
>
> Neither.  It is the nature of floating point representational error due to 
> the mismatch between binary (base 2) and decimal (base 10).  All math 
> libraries that utilize base 2 are subject to this problem.
>
>> or something I can do differently?.
>
> Yes.  Save your division to the end (which you did) OR update to v1.9 
> which I tested to return 90.04 (specific case) OR use integer math OR 
> switch your applications number system from base 10 to base 2.
>
> Regards,
>
> Rodd Graham, Consultant
> Graham Automation Systems, LLC
>
>
Rodd Graham Re: The Lost Penny
on Fri, 13 Mar 2009 14:48:25 +0000
Hello Ernie,

> The bit I wanted to hear was that version 1.9 gave the correct result.

Remember this is a specific case which should not be extrapolated into a 
general conclusion.

> 
> While I understand your comments re:  binary vs decimal,  surely we
> should'nt be concerned
> nowadays about getting wrong answers when we multiply, divide, then
> round a
> few small
> numbers?.

I agree, but why were you concerned whether it was .03 or .04?  Isn't this 
just a small number?

However, I don't think you fully understand the binary vs decimal problem. 
 It is not that we work in decimal and computers work in binary.  The problem 
is that mathematics (not computers) in different number bases do not have 
exact equivalence in representations:

Example:

1/3 in base10 (decimal) = 0.33333 with the 3 repeating to infinity.  However, 
in base3, the number can be exactly written as 0.1 (assuming common convention 
of using numeric digit symbols for alternative numeric bases)

I challenge you to represent this 1/3 precisely in base10 with resorting 
to a mathematical notation to deal with the infinite representation.  This 
is the problem with base2 representing base10 numbers.  There are numbers 
that we see as finite and succinct in base10 that take infinite sequences 
to represent in base2.  The computer cannot store infinite sequences nor 
does it support a symbolic notation to representing repeating infinities. 
 Rather the computer uses the closest value that it can represent in base2.

In your specific case, the value was slightly lower than .035 which causes 
the round function to select .03 while decimally (base10) you consider the 
value .04.

> I thought, as a tempory measure, of using something like ROUND ( ROUND
> (
> <Exp> , 8 ) , 2 ).
> This works in my case, but seems a bit clumsy for general use.
> Your comment about leaving divisions to the end is interesting. Does
> this
> allow the
> floating point package to retain more intermediate accuracy?

Divisions frequently introduce fractional components and the fractional components 
are where the representational error exists.  Defering the fractional components 
as late as possible in the calculation reduces (but does not eliminate) the 
propogation of the representational error.

FWIW, my solution to your issue is to accept .03 as a valid result.  Realize 
that there are multiple generally accepted ROUNDing operations besides NEAREST 
including FLOOR, CEILING, BANKERS, etc.  As such, I would just declare that 
my Xbase++ application implements the Xbase++ ROUNDing operation which is 
only specified to be acceptably close and subject to change.  Put another 
way, I am not under any legal requirement to care about fractions of pennies.

You will not eliminate your representational problem until you either use 
integer math (not subject to fractions/not subject to representational error 
between number bases) OR you utilize a BCD math library that does all math 
in decimal even though it is performed on a binary computer.

Regards,

Rodd Graham, Consultant
Graham Automation Systems, LLC
Carlos Beling Re: The Lost Penny
on Fri, 13 Mar 2009 09:53:32 -0300
Hello Hernie:
good morning.
I always use parenthesis in the formulas for defining the priorities, as follows:

ROUND(  ( (81.85 / 100) * 110 ) ,2 )

Beling
Best regards

Ernie Barlow escreveu:
> Morning,
> 
>  Is this a bug, a "feature", or something I can do differently?.
> 
>  I was checking the result of a sales price calculation on a report when I
> came across:
> 
>     ROUND(  ( 81.85  / 100 * 110 ) ,2 )    -  which gave 90.03.
> 
>  All three of my calculators said this should be 90.04. Additionally Clipper
> 5.3
>  and the latest incarnation of FoxPro both gave the result as 90.04.
> 
>  Change the order of the operands to :
> 
>     ROUND(  ( 81.85  * 110 / 100 ) ,2 )   -  we now get 90.04
> 
>  Looking further, the result of the first expression is 90.034999999999990,
> and the
>  second is 90.035000000000000
> 
>  Sorry if this ground has been covered before but I don't come here very
> often.
>  I use Alaska 1.82.306
> 
> 
>  Regards
> 
>  Ernie Barlow
> 
> 
> 
> 
> 
>
Hubert Brandel Re: The Lost Penny
on Fri, 13 Mar 2009 16:50:47 +0100
Hi,

1.90.331 give back same way like 1.82.x -> 90.03 / 90.04
1.90.350 give back 90.04 / 90.04

Bye
Hubert



----------------

Ich empfehle:  www.xbaseforum.de  (in deutsch)

Homepage:

German  - www.familie-brandel.de/index.htm
English - www.familie-brandel.de/index_e.htm
G. HenzlerRe: The Lost Penny
on Fri, 13 Mar 2009 18:19:33 +0100
Is there an Option/function to set the rounding behavior?? I don't 
remeber...


Mfg

Gerhard

"Hubert Brandel" <hubert.brandel@gmx.de> schrieb im Newsbeitrag 
news:1c4097fb$289b5f0e$c75@news.alaska-software.com...
> Hi,
>
> 1.90.331 give back same way like 1.82.x -> 90.03 / 90.04
> 1.90.350 give back 90.04 / 90.04
>
> Bye
> Hubert
>
>
>
> ----------------
>
> Ich empfehle:  www.xbaseforum.de  (in deutsch)
>
> Homepage:
>
> German  - www.familie-brandel.de/index.htm
> English - www.familie-brandel.de/index_e.htm
Terry WolfeRe: The Lost Penny
on Fri, 13 Mar 2009 23:59:44 -0500
Hi Ernie,

I struggled with this for some time and finally decided on the following
instead of the function 'round()', I use 'TwoPlace()'.  Only use this as the
final formatting function call just before displaying the results of your
math functions.  By adding 1 millionth of a cent to the result before
truncating the number you hide most if not all 'lost penny' problems.

twoplace( 81.85  / 100 * 110  ) -> 90.04  in all versions of
xbase/clipper/foxpro I have tested.

//----------------------------------------
FUNCTION TwoPlace(num)
RETURN(val(str(num+.00000001,10,2)))
 EOF TwoPlace

HTH,
Terry

"Ernie Barlow" <nospam@nospam.com> wrote in message
news:59b196cb$51f6b182$28ca@news.alaska-software.com...
> Morning,
>
>  Is this a bug, a "feature", or something I can do differently?.
>
>  I was checking the result of a sales price calculation on a report when I
> came across:
>
>     ROUND(  ( 81.85  / 100 * 110 ) ,2 )    -  which gave 90.03.
>
>  All three of my calculators said this should be 90.04. Additionally
Clipper
> 5.3
>  and the latest incarnation of FoxPro both gave the result as 90.04.
>
>  Change the order of the operands to :
>
>     ROUND(  ( 81.85  * 110 / 100 ) ,2 )   -  we now get 90.04
>
>  Looking further, the result of the first expression is
90.034999999999990,
> and the
>  second is 90.035000000000000
>
>  Sorry if this ground has been covered before but I don't come here very
> often.
>  I use Alaska 1.82.306
>
>
>  Regards
>
>  Ernie Barlow
>
>
>
>
>
>
Joe Carrick Re: The Lost Penny
on Sat, 14 Mar 2009 08:46:47 -0700
Hi Terry,

Interesting... I've been using the following with the same results for 
quite a while.

FUNCTION MxRound( nValue, nDecimals )
RETURN (val(str(nValue,,nDecimals)))

The only difference really is that my function allows any number of 
decimal places including zero.  You can actually use a calculation in 
the nValue parameter and get the correct rounding. 

What this really points out is that str() gives accurate results while 
round() might not.  It is possible that the latest version of Xbase++ 
has fixed this but we don't need to quit using the functions that we trust.

-Joe


Terry Wolfe wrote:
> Hi Ernie,
>
> I struggled with this for some time and finally decided on the following
> instead of the function 'round()', I use 'TwoPlace()'.  Only use this as the
> final formatting function call just before displaying the results of your
> math functions.  By adding 1 millionth of a cent to the result before
> truncating the number you hide most if not all 'lost penny' problems.
>
> twoplace( 81.85  / 100 * 110  ) -> 90.04  in all versions of
> xbase/clipper/foxpro I have tested.
>
> //----------------------------------------
> FUNCTION TwoPlace(num)
> RETURN(val(str(num+.00000001,10,2)))
>  EOF TwoPlace
>
> HTH,
> Terry
>
> "Ernie Barlow" <nospam@nospam.com> wrote in message
> news:59b196cb$51f6b182$28ca@news.alaska-software.com...
>   
>> Morning,
>>
>>  Is this a bug, a "feature", or something I can do differently?.
>>
>>  I was checking the result of a sales price calculation on a report when I
>> came across:
>>
>>     ROUND(  ( 81.85  / 100 * 110 ) ,2 )    -  which gave 90.03.
>>
>>  All three of my calculators said this should be 90.04. Additionally
>>     
> Clipper
>   
>> 5.3
>>  and the latest incarnation of FoxPro both gave the result as 90.04.
>>
>>  Change the order of the operands to :
>>
>>     ROUND(  ( 81.85  * 110 / 100 ) ,2 )   -  we now get 90.04
>>
>>  Looking further, the result of the first expression is
>>     
> 90.034999999999990,
>   
>> and the
>>  second is 90.035000000000000
>>
>>  Sorry if this ground has been covered before but I don't come here very
>> often.
>>  I use Alaska 1.82.306
>>
>>
>>  Regards
>>
>>  Ernie Barlow
>>
>>
>>
>>
>>
>>
>>     
>
>
>