home | O'Reilly's CD bookshelfs | FreeBSD | Linux | Cisco | Cisco Exam  


2.2. 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 module (also in Chapter 7 of Programming Perl ); we use sprintf in Recipe 2.3 ; Volume 2, Section 4.2.2 of The Art of Computer Programming


Previous: 2.1. Checking Whether a String Is a Valid Number Perl Cookbook Next: 2.3. Rounding Floating-Point Numbers
2.1. Checking Whether a String Is a Valid Number Book Index 2.3. Rounding Floating-Point Numbers