RE: Math weirdness
Mike, I don't think there's any JVM args to do this, but there are properties of some of the math objects that seem to be able to do this. But there are also half a million posts on how to work around this problem in Java (ha). Kudos for an excellent explanation of floating point precision problems... nicely done! -Mark Mark A. Kruger, MCSE, CFG (402) 408-3733 ext 105 Skype: markakruger www.cfwebtools.com www.coldfusionmuse.com www.necfug.com -Original Message- From: Mike Chabot [mailto:mcha...@gmail.com] Sent: Thursday, February 03, 2011 6:24 PM To: cf-talk Subject: Re: Math weirdness Jen, This quirk is due to the difference between exact integer math and approximate floating point math. Some imprecision is introduced when CF converts the decimal number that you see to a binary floating point number that the computer performs the math function on. Some decimal numbers cannot be exactly represented by binary floating point numbers, so floating point math often has unexpected results. If you find this idea confusing, think of the more familiar base-10 number of 1/3. It looks exact in that representation, but presented another way that number is actually 0.33...(repeating). Infinitely repeating numbers also exist when using base-2 binary instead of base-10, but with a different set of fractions that cannot be represented without a loss of precision, such as 0.1. Computers cannot handle infinitely repeating numbers, so some rounding and loss of precision occurs. You should never see the precision problem with common integer math like incrementing loop counters. This floating point precision behavior impacts most programming languages, not just ColdFusion and Java. In strongly-typed platforms, such as .NET and SQL Server, you can tell the complier that a number is a decimal and that you want math performed on that number to be precise fixed-point math, not imprecise floating point math. I'm not sure of any good way to pull this off in ColdFusion. Possibly something with the javacast function would work, but that would be messy code. I just use a rounding function. The question of why does ColdFusion use imprecise floating point math instead of exact fixed-point math is one I don't have the answer to without researching it. It is annoying to have pass all math involving decimals through a rounding function, and it is easy to forget to do this. Does anyone know of a good way to fix this problem on a site-wide basis? It would be nice if ColdFusion was smart enough to know that addition and subtraction involving base-10 numbers with only one decimal point cannot result in a number with greater than one decimal point of precision. #3.2 - 3.2 + 8 - 8# = 0 #3.2 + 8 - 3.2 - 8# = -8.881784197E-016 #0.6/0.2# = 3 #0.6/0.2 - 3# = -4.4408920985E-016 -Mike Chabot On Thu, Feb 3, 2011 at 3:56 PM, Jen McVicker snarkmeis...@gmail.com wrote: OK, a coworker sent this over to me and I am puzzled: cfset number1 = evaluate(12.5 * 1.1) cfset number2 = 12.5 * 1.1 cfset number3 = 13.75 cfset testEval = number3 - number1 cfset testNoEval = number3 - number2 cfoutput number1 (12.5 * 1.1): strong#number1#/strongbr number2 (#number2#): strong#number2#/strongbr number3 (#number3#): strong#number3#/strongbr #number3# - #number1#: strong#testEval#/strongBR #number3# - #number2#: strong#testNoEval#/strongBR cfif number3 eq number1Number3 equals number1BR cfelseNumber3 does NOT equal number1BR/cfif cfif number3 eq number2Number3 equals number2BR cfelseNumber3 does NOT equal number2BR/cfif /cfoutput Results in: number1 (evaluate(12.5 * 1.1)): 13.75 number2 (12.5 * 1.1): 13.75 number3 (13.75): 13.75 13.75 - 13.75: 0 13.75 - 13.75: -1.7763568394E-015 Number3 equals number1 Number3 does NOT equal number2 Obviously number2 is set to a reference of the expression rather than the actual value that is returned. But since the variable outputs as 13.75, why does it make a difference? Can someone explain it to me in small words so that I will understand? ;-) Jen Perkins McVicker Adobe Certified ColdFusion Developer Email: jen.mcvic...@gmail.com Linked In: http://www.linkedin.com/in/jmcvicker ~| Order the Adobe Coldfusion Anthology now! http://www.amazon.com/Adobe-Coldfusion-Anthology/dp/1430272155/?tag=houseoffusion Archive: http://www.houseoffusion.com/groups/cf-talk/message.cfm/messageid:341859 Subscription: http://www.houseoffusion.com/groups/cf-talk/subscribe.cfm Unsubscribe: http://www.houseoffusion.com/groups/cf-talk/unsubscribe.cfm
Math weirdness
OK, a coworker sent this over to me and I am puzzled: cfset number1 = evaluate(12.5 * 1.1) cfset number2 = 12.5 * 1.1 cfset number3 = 13.75 cfset testEval = number3 - number1 cfset testNoEval = number3 - number2 cfoutput number1 (12.5 * 1.1): strong#number1#/strongbr number2 (#number2#): strong#number2#/strongbr number3 (#number3#): strong#number3#/strongbr #number3# - #number1#: strong#testEval#/strongBR #number3# - #number2#: strong#testNoEval#/strongBR cfif number3 eq number1Number3 equals number1BR cfelseNumber3 does NOT equal number1BR/cfif cfif number3 eq number2Number3 equals number2BR cfelseNumber3 does NOT equal number2BR/cfif /cfoutput Results in: number1 (evaluate(12.5 * 1.1)): 13.75 number2 (12.5 * 1.1): 13.75 number3 (13.75): 13.75 13.75 - 13.75: 0 13.75 - 13.75: -1.7763568394E-015 Number3 equals number1 Number3 does NOT equal number2 Obviously number2 is set to a reference of the expression rather than the actual value that is returned. But since the variable outputs as 13.75, why does it make a difference? Can someone explain it to me in small words so that I will understand? ;-) Jen Perkins McVicker Adobe Certified ColdFusion Developer Email: jen.mcvic...@gmail.com Linked In: http://www.linkedin.com/in/jmcvicker ~| Order the Adobe Coldfusion Anthology now! http://www.amazon.com/Adobe-Coldfusion-Anthology/dp/1430272155/?tag=houseoffusion Archive: http://www.houseoffusion.com/groups/cf-talk/message.cfm/messageid:341849 Subscription: http://www.houseoffusion.com/groups/cf-talk/subscribe.cfm Unsubscribe: http://www.houseoffusion.com/groups/cf-talk/unsubscribe.cfm
re: Math weirdness
Whoa, creepy. That is certainly very odd. From: Jen McVicker snarkmeis...@gmail.com Sent: Thursday, February 03, 2011 3:57 PM To: cf-talk cf-talk@houseoffusion.com Subject: Math weirdness OK, a coworker sent this over to me and I am puzzled: cfset number1 = evaluate(12.5 * 1.1) cfset number2 = 12.5 * 1.1 cfset number3 = 13.75 cfset testEval = number3 - number1 cfset testNoEval = number3 - number2 cfoutput number1 (12.5 * 1.1): strong#number1#/strongbr number2 (#number2#): strong#number2#/strongbr number3 (#number3#): strong#number3#/strongbr #number3# - #number1#: strong#testEval#/strongBR #number3# - #number2#: strong#testNoEval#/strongBR cfif number3 eq number1Number3 equals number1BR cfelseNumber3 does NOT equal number1BR/cfif cfif number3 eq number2Number3 equals number2BR cfelseNumber3 does NOT equal number2BR/cfif /cfoutput Results in: number1 (evaluate(12.5 * 1.1)): 13.75 number2 (12.5 * 1.1): 13.75 number3 (13.75): 13.75 13.75 - 13.75: 0 13.75 - 13.75: -1.7763568394E-015 Number3 equals number1 Number3 does NOT equal number2 Obviously number2 is set to a reference of the expression rather than the actual value that is returned. But since the variable outputs as 13.75, why does it make a difference? Can someone explain it to me in small words so that I will understand? ;-) Jen Perkins McVicker Adobe Certified ColdFusion Developer Email: jen.mcvic...@gmail.com Linked In: http://www.linkedin.com/in/jmcvicker ~| Order the Adobe Coldfusion Anthology now! http://www.amazon.com/Adobe-Coldfusion-Anthology/dp/1430272155/?tag=houseoffusion Archive: http://www.houseoffusion.com/groups/cf-talk/message.cfm/messageid:341851 Subscription: http://www.houseoffusion.com/groups/cf-talk/subscribe.cfm Unsubscribe: http://www.houseoffusion.com/groups/cf-talk/unsubscribe.cfm
Re: Math weirdness
On 2/3/2011 12:56 PM, Jen McVicker wrote: Can someone explain it to me in small words so that I will understand? ;-) Computers do not understand decimal (base 10) numbers. They only truly understand binary (base 2) numbers. Sometimes when converting back and forth between the base 10 numbers we humans like to use and the base 2 numbers that computers have to use, small differences in rounding occur. 99.9% of the time, the computer systems handle these and we humans can ignore the base 2 nature of computers. But sometimes we really must be computer programmers and understand the real world of binary computers. ~| Order the Adobe Coldfusion Anthology now! http://www.amazon.com/Adobe-Coldfusion-Anthology/dp/1430272155/?tag=houseoffusion Archive: http://www.houseoffusion.com/groups/cf-talk/message.cfm/messageid:341852 Subscription: http://www.houseoffusion.com/groups/cf-talk/subscribe.cfm Unsubscribe: http://www.houseoffusion.com/groups/cf-talk/unsubscribe.cfm
Re: Math weirdness
These are the pitfalls of a dynamically typed language, and FLOAT/INT conversions. Your number1 is a string, number2 is a Double, and your number 3 is a string: cfoutput number3 is #number3.getClass().getName()#br / number2 is #number2.getClass().getName()#br / number1 is #number1.getClass().getName()#br / /cfoutput If you do val() they will equal out: cfif val(number3) eq val(number2)Number3 equals number2BR cfelseNumber3 does NOT equal number2BR/cfif From http://docs.sun.com/source/806-3568/ncg_goldberg.html#680, the result of a floating-point calculation must often be rounded in order to fit back into its finite representation. This rounding error is the characteristic feature of floating-point computation. Checkout this code: cfoutput #(0.1 * 0.1) EQ 0.01# !--- not equal! --- #0.1 * 0.1# !--- 0.1 multiplied by 0.1 is actually 0.01, so why aren't they equal? --- #javacast(bigDecimal, 0.1 * 0.1)# !--- results in 0.010002 --- /cfoutput If you need strict computation, stick to Doubles or bigDecimals all the time, and don't rely on implicit conversions. Also this is not a CF thing or a Java thing, other languages plague this too i.e Python (for division, 3/4 is different from 3.0/4.0) and .NET (http://stefanoricciardi.com/2010/03/02/comparing-floating-point-numbers/), and PHP (http://it.slashdot.org/story/11/01/06/1820208/PHP-Floating-Point-Bug-Crashes-Servers http://it.slashdot.org/story/11/01/06/1820208/PHP-Floating-Point-Bug-Crashes-Servers?from=rss or just start typing in google instant, php floating... and you'll see all the suggestions hehe) On 2/3/2011 12:56 PM, Jen McVicker wrote: number1 (evaluate(12.5 * 1.1)): 13.75 number2 (12.5 * 1.1): 13.75 number3 (13.75): 13.75 13.75 - 13.75: 0 13.75 - 13.75: -1.7763568394E-015 Number3 equals number1 Number3 does NOT equal number2 Obviously number2 is set to a reference of the expression rather than the actual value that is returned. But since the variable outputs as 13.75, why does it make a difference? Can someone explain it to me in small words so that I will understand? ;-) Jen Perkins McVicker Adobe Certified ColdFusion Developer Email: jen.mcvic...@gmail.com Linked In: http://www.linkedin.com/in/jmcvicker ~| Order the Adobe Coldfusion Anthology now! http://www.amazon.com/Adobe-Coldfusion-Anthology/dp/1430272155/?tag=houseoffusion Archive: http://www.houseoffusion.com/groups/cf-talk/message.cfm/messageid:341853 Subscription: http://www.houseoffusion.com/groups/cf-talk/subscribe.cfm Unsubscribe: http://www.houseoffusion.com/groups/cf-talk/unsubscribe.cfm
Re: Math weirdness
Jen, This quirk is due to the difference between exact integer math and approximate floating point math. Some imprecision is introduced when CF converts the decimal number that you see to a binary floating point number that the computer performs the math function on. Some decimal numbers cannot be exactly represented by binary floating point numbers, so floating point math often has unexpected results. If you find this idea confusing, think of the more familiar base-10 number of 1/3. It looks exact in that representation, but presented another way that number is actually 0.33...(repeating). Infinitely repeating numbers also exist when using base-2 binary instead of base-10, but with a different set of fractions that cannot be represented without a loss of precision, such as 0.1. Computers cannot handle infinitely repeating numbers, so some rounding and loss of precision occurs. You should never see the precision problem with common integer math like incrementing loop counters. This floating point precision behavior impacts most programming languages, not just ColdFusion and Java. In strongly-typed platforms, such as .NET and SQL Server, you can tell the complier that a number is a decimal and that you want math performed on that number to be precise fixed-point math, not imprecise floating point math. I'm not sure of any good way to pull this off in ColdFusion. Possibly something with the javacast function would work, but that would be messy code. I just use a rounding function. The question of why does ColdFusion use imprecise floating point math instead of exact fixed-point math is one I don't have the answer to without researching it. It is annoying to have pass all math involving decimals through a rounding function, and it is easy to forget to do this. Does anyone know of a good way to fix this problem on a site-wide basis? It would be nice if ColdFusion was smart enough to know that addition and subtraction involving base-10 numbers with only one decimal point cannot result in a number with greater than one decimal point of precision. #3.2 - 3.2 + 8 - 8# = 0 #3.2 + 8 - 3.2 - 8# = -8.881784197E-016 #0.6/0.2# = 3 #0.6/0.2 - 3# = -4.4408920985E-016 -Mike Chabot On Thu, Feb 3, 2011 at 3:56 PM, Jen McVicker snarkmeis...@gmail.com wrote: OK, a coworker sent this over to me and I am puzzled: cfset number1 = evaluate(12.5 * 1.1) cfset number2 = 12.5 * 1.1 cfset number3 = 13.75 cfset testEval = number3 - number1 cfset testNoEval = number3 - number2 cfoutput number1 (12.5 * 1.1): strong#number1#/strongbr number2 (#number2#): strong#number2#/strongbr number3 (#number3#): strong#number3#/strongbr #number3# - #number1#: strong#testEval#/strongBR #number3# - #number2#: strong#testNoEval#/strongBR cfif number3 eq number1Number3 equals number1BR cfelseNumber3 does NOT equal number1BR/cfif cfif number3 eq number2Number3 equals number2BR cfelseNumber3 does NOT equal number2BR/cfif /cfoutput Results in: number1 (evaluate(12.5 * 1.1)): 13.75 number2 (12.5 * 1.1): 13.75 number3 (13.75): 13.75 13.75 - 13.75: 0 13.75 - 13.75: -1.7763568394E-015 Number3 equals number1 Number3 does NOT equal number2 Obviously number2 is set to a reference of the expression rather than the actual value that is returned. But since the variable outputs as 13.75, why does it make a difference? Can someone explain it to me in small words so that I will understand? ;-) Jen Perkins McVicker Adobe Certified ColdFusion Developer Email: jen.mcvic...@gmail.com Linked In: http://www.linkedin.com/in/jmcvicker ~| Order the Adobe Coldfusion Anthology now! http://www.amazon.com/Adobe-Coldfusion-Anthology/dp/1430272155/?tag=houseoffusion Archive: http://www.houseoffusion.com/groups/cf-talk/message.cfm/messageid:341857 Subscription: http://www.houseoffusion.com/groups/cf-talk/subscribe.cfm Unsubscribe: http://www.houseoffusion.com/groups/cf-talk/unsubscribe.cfm