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.40
It 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 ...
Get Perl Cookbook now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.