# SPUG: Incorrect subtraction result

Ben Reser ben at reser.org
Tue Aug 26 03:09:29 PDT 2008

On Tue, Aug 26, 2008 at 2:34 AM, Christopher Howard <choward at indicium.us> wrote:
> Hello.  I was hoping someone might help me figure what is wrong with some code I wrote.  I wrote this class, and I gave it a member function that is designed to act as a change calculator.  That is, I pass it the total value of the purchase and the amount of money the (virtual) customer gave me, and it calculates how much of each kind of change to give (dollars, quarters, dimes, etc.)
>
> However, when I test it with the values 5.87 and 20.63 (meaning 14.76 of change is needed), I get a strange math error.
>
> Here is some debugging results:
> Starting amount: 14.76
> Value of currency unit: 10
> Amount remaining after subtraction: 4.76
> Value of currency unit: 1
> Amount remaining after subtraction: 3.76
> Value of currency unit: 1
> Amount remaining after subtraction: 2.76
> Value of currency unit: 1
> Amount remaining after subtraction: 1.76
> Value of currency unit: 1
> Amount remaining after subtraction: 0.759999999999998
> Value of currency unit: 0.25
> Amount remaining after subtraction: 0.509999999999998
> Value of currency unit: 0.25
> Amount remaining after subtraction: 0.259999999999998
> Value of currency unit: 0.25
> Amount remaining after subtraction: 0.00999999999999801
>
> As you can see, after 1 is subtracted from 1.76, the result is 0.759999999999998 (not good for my program).  I ran this on another Linux system, and the results were the same.

Strongly recommend reading:
http://perldoc.perl.org/perlnumber.html#Numeric-operators-and-numeric-conversions

However, the problem is you're using print and giving it a floating
point value when it's expecting a string.  So perl implicitly converts
the floating point to a string.  However, this causes a loss in
precision that you don't desire.  So the problem isn't in the
calculation but your output.

The following diff will fix the problem:

--- ChangeCalculator.pm~        2008-08-26 03:06:59.000000000 -0700
+++ ChangeCalculator.pm 2008-08-26 03:00:41.000000000 -0700
@@ -13,10 +13,10 @@
my \$unitValue = \$_;
my \$timesUsed = 0;
until(\$amtOwed<\$unitValue) {
-      print "Value of currency unit: ", \$unitValue, "\n"; #for debugging
+      printf "Value of currency unit: %.2f\n", \$unitValue; #for debugging
\$timesUsed++;
\$amtOwed = \$amtOwed - \$unitValue;
-      print "Amount remaining after subtraction: ", \$amtOwed, "\n";
#for debugging
+      printf "Amount remaining after subtraction: %.2f\n", \$amtOwed;
#for debugging
}
push @results, [\$unitValue, \$timesUsed];
}

More information about the spug-list mailing list