Comparing Floating-Point Numbers
Problem
Floating-point arithmetic isn’t precise. You want to compare two floating-point numbers and know if they’re equal when carried out to a certain number of decimal places. Most of the time, this is the way you should compare floating-point numbers for equality.
Solution
Use sprintf to format the numbers to a certain
number of decimal places, then compare the resulting strings:
# equal(NUM1, NUM2, ACCURACY) : returns true if NUM1 and NUM2 are
# equal to ACCURACY number of decimal places
sub equal {
my ($A, $B, $dp) = @_;
return sprintf("%.${dp}g", $A) eq sprintf("%.${dp}g", $B);
}Alternatively, store the numbers as integers by assuming the decimal place.
Discussion
You need the equal routine because most
computers’ floating-point representations aren’t
accurate. See the Introduction for a discussion of this issue.
If you have a fixed number of decimal places, as with currency, you
can sidestep the problem by storing your values as integers. Storing
$3.50 as 350 instead of
3.5 removes the need for floating-point values.
Reintroduce the decimal point on output:
$wage = 536; # $5.36/hour
$week = 40 * $wage; # $214.40
printf("One week's wage is: \$%.2f\n", $week/100);
One week's wage is: $214.40It rarely makes sense to compare to more than 15 decimal places.
See Also
The sprintf function in perlfunc
(1) and Chapter 3 of Programming Perl
; the entry on $# in the
perlvar(1) manpage and Chapter 2 of
Programming Perl; the documentation for the standard Math::BigFloat ...