SPUG: Incorrect subtraction result

Christopher Howard choward at indicium.us
Tue Aug 26 02:34:06 PDT 2008


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.

Here is the class itself (released under GPLv3):
package ChangeCalculator;
sub new {
    $self = { UNITS=>[ 20, 10, 5, 1, 0.25, 0.1, 0.05, 0.01 ] };
    bless $self, 'ChangeCalculator'; return $self;
}
#array calculate(scalar, scalar)
sub calculate {
    my $self = shift;
    my $amtOwed = $_[1] - $_[0];
    print "Starting amount: ", $amtOwed, "\n"; #for debugging
    my @results;
    foreach(@{$self->{UNITS}}) {
    my $unitValue = $_;
    my $timesUsed = 0;
    until($amtOwed<$unitValue) {
        print "Value of currency unit: ", $unitValue, "\n"; #for debugging
        $timesUsed++;
        $amtOwed = $amtOwed - $unitValue;
        print "Amount remaining after subtraction: ", $amtOwed, "\n"; 
#for debugging
    }
    push @results, [$unitValue, $timesUsed];
    }
    return @results;
}

1;

And here is the script used to test it:
#!/usr/bin/env perl
use strict;
use warnings;
use ChangeCalculator;
my $cc = new ChangeCalculator;
my @test = $cc->calculate(5.87, 20.63);

Thank you for any time you would be willing to give looking this over.  
I can't seem to figure out what I have done wrong.  Does this have 
something to do with the way Perl handles data types?



More information about the spug-list mailing list