comparing floating point numbers

T

Thens

Hi,

I have a problem comparing floating point numbers. After a lot of googling and docs I found the issue to be because of the internal floating point representation.

Here is a sample program that explains that

#!/usr/local/bin/perl

use strict;
use warnings;

my ( $num, $num1, $num2 );

$num = 1.8;
$num1 = ( $num * (1 + (10/100) ) ); # $num + 10% $num => 1.98

print "Number :", sprintf "%2.20f \n" , $num;
print "Number +10% :", sprintf "%2.20f \n", $num1;

$num2 = 1.98;
print "Number +10% :", sprintf "%30.20f \n", $num2;

if ( $num1 != $num2 ) {
print "FIRST PASS >> $num1 is not equal to $num2 !! \n";
}
if ( ($num1+0.1) != ($num2+.1) ) {
print "SECOND PASS >> $num1 is not eqaul to $num2 !!\n";
}


This prints

FIRST PASS >> 1.98 is not equal to 1.98 !!


I understand this is because of the floating point representation. Then I tried to solve it by adding 0.1 at both the ends and then comparing the numbers. THis seems to have solved the problem. My question is, Is this a reliable solution.

While searching the group archive, I found this can be achieved by checking for a small delta like

$delta = 0.0001

if ( abs ( $num1 - $num2 ) < $delta ) {
# Now they are eual
}
...


I wanted to know under what circumstances may adding 0.1 at both ends can fail.

Thanks and Regards,
Thens.
 
M

Mothra

Thens said:
Hi,

I have a problem comparing floating point numbers. After a lot of
googling and docs I found the issue to be because of the internal floating
point representation.[snipped]

Here is what I use to compare two floating numbers.

until ( equal( $tmp_rise_2, $tmp_rise_3, 8 ) ) {
do stuff....
}

sub equal {

#
#
# FUNCTIONAL SEQUENCE for equal
#
# _GIVEN
#
# Two floating point numbers and Accuracy
#
# _THEN
#
# Use sprintf to format the numbers to Accuracy
# number of decimal places
#
# _RETURN
#
# True if the numbers are equal
#
my ( $A, $B, $dp ) = @_;

return sprintf( "%.${dp}g", $A ) eq sprintf( "%.${dp}g", $B );
}


hope this helps

Mothra
 
G

Greg Bacon

: [...]
:
: While searching the group archive, I found this can be achieved by
: checking for a small delta like
:
: $delta = 0.0001
:
: if ( abs ( $num1 - $num2 ) < $delta ) {
: # Now they are eual
: }
:
: I wanted to know under what circumstances may adding 0.1 at both
: ends can fail.

That depends on the nature of your computation. Remember that computers
use finite-precision arithmetic, the way you structure computations can
hurt you, e.g., dividing by a very small number or subtracting numbers
close values can produce serious rounding errors.

See "What Every Computer Scientist Should Know About Floating-Point
Arithmetic" at

http://docs.sun.com/source/806-3568/ncg_goldberg.html

Even checking for membership in some epsilon-neighborhood isn't
always sufficient:

Incidentally, some people think that the solution to such
anomalies is never to compare floating-point numbers for
equality, but instead to consider them equal if they are within
some error bound E. This is hardly a cure-all because it raises
as many questions as it answers. What should the value of E be?
If x < 0 and y > 0 are within E, should they really be
considered to be equal, even though they have different signs?
Furthermore, the relation defined by this rule,

a ~ b <=> |a - b| < E

is not an equivalence relation because a ~ b and b ~ c does
not imply that a ~ c.

ibid.

Greg
 
M

Michael P. Broida

Thens said:
Hi,

I have a problem comparing floating point numbers.

One of the things you need to learn about floating point
numbers is:
NEVER compare them for equality (or inequality).


Mike
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,763
Messages
2,569,562
Members
45,038
Latest member
OrderProperKetocapsules

Latest Threads

Top