Author | Topic: The Lost Penny | |
---|---|---|
Ernie Barlow | The 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 Barlow | Re: 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. Henzler | Re: 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 Wolfe | Re: 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 >> >> >> >> >> >> >> > > > |