# perl floating point problem

Discussion in 'Perl Misc' started by info@oliverhallmann.de, Nov 8, 2007.

1. ### Guest

#!/usr/local/bin/perl

my \$i=2.55;
\$i=\$i*100;
print "\$i\n";
my \$j=int(\$i);
print "\$j\n";

output:
255
254

can someone explain that to me?

, Nov 8, 2007

2. ### Jürgen ExnerGuest

wrote:
> #!/usr/local/bin/perl
>
> my \$i=2.55;
> \$i=\$i*100;
> print "\$i\n";
> my \$j=int(\$i);
> print "\$j\n";
>
> output:
> 255
> 254
>
> can someone explain that to me?

You must have missed "Basics of Computer Numerics".
You must also have missed the documentation for int() where it explicitely
explains this behaviour.
You could also check 'perldoc -q 999' for a very brief introduction of why
using floating point numbers has it quirks in Perl, too, just like in any
other standard programming language.

jue

Jürgen Exner, Nov 8, 2007

3. ### Guest

On Nov 8, 8:09 am, wrote:
>
> #!/usr/local/bin/perl
> my \$i=2.55;
> \$i=\$i*100;
> print "\$i\n";
> my \$j=int(\$i);
> print "\$j\n";
>
> output:
> 255
> 254
>
> can someone explain that to me?

Basically, you're wondering why:

if (2.55*100 == 255) {
print "Equal\n";
} else {
print "Not equal\n";
}

prints "Not equal" when 2.55 multiplied by 100 can't be anything but
255.

This is a behavior common to many languages and platforms, and not
just Perl. So let me begin by explaining it this way:

You know how impossible to represent some fractional numbers (such
as 1/3) in decimal notation? You might consider writing 1/3 as:

0.333

or as:

0.33333333333

or even:

0.3333333333333333333333333333333333333

But the truth is, no matter how many 3s you use, the number you write
will never fully equal 1/3 (note that this isn't true for 1/2, which
is easily written as 0.5).

(Yes, mathematicians will sometimes use a bar over the last 3 to
denote that it repeats indefinitely, but as far as I know, no computer
uses this notation.)

Well, certain numbers cannot be accurately represented in binary
notation, either. One such number is 2.55, the one you used in your
script.

The number 2.5 can be represented in binary notation like this:

10.1

(That's 2**1 + 0 + 2**-1.)

The number 2.625 can be represented in binary notation like this:

10.101

(That's 2**1 + 0 + 2**-1 + 0 + 2**-3.)

But the number 2.55 cannot be accurately represented in binary
notation. The closest Perl (and many computers) can come up with is:

10.100011001100110011001100110011001100110011001100110

(That's 2**1 + 0 + 2**-1 + 0 + 0 + 0 + 2**-5 + 2**-6 + etc.)

Notice that this number has a repeating part after its decimal
point (or should I say "binary point"?). Indeed, the "0011" part
repeating part, so this number is as close as it'll get to 2.55
(which, admittedly, is VERY close). But even though this number is
very close to 2.55, it's technically still not exactly that.

Likewise, when you mutiply this number with 100, you get a number
that's very close to 255, but not quite that value. In fact, the
value Perl internally creates when you multiply 2.55 with 100 is:

11111110.111111111111111111111111111111111111111111111

which is roughly equivalent to 254.9999999999 .

Here's something fun to try: Try printing out the difference
between 255 and 2.55*100:

perl -le "print 255 - 2.55*100"

This will print out something like:

2.8421709430404e-014

The "e-014" part tells us that that's an extremely small number. Yet
it's still a non-zero number, meaning that Perl thinks that 2.55*100
is smaller (though not by much) than 255. And since 2.55*100 is
considered to be smaller than 255, it should now make sense that
int(2.55*100) returns 254 (instead of 255).

It just so happens that when we try to print out the value
2.55*100, it will round to the nearest 0.00000000... "something-place"
and print out 255, just like it will when running the following Perl
commands:

# These both print 255:
perl -le "print 2.55*100"
perl -le "print 254.99999999999999"

The reason it prints out "255" is not because Perl thinks the number
you passed it is 255, but rather one that rounds to 255 when printed.

So to Perl, 2.55*100 isn't equivalent to 255 -- it's just that the
print() statement rounds a value like 254.99999999999999 to 255 before
printing (since most humans would rather see it rounded to 255 since
it's so close).

I hope this explanation helps.

-- Jean-Luc Romano

P.S. You can read more about how Perl (and most computers) store
double precision numbers (and even single precision) in memory by
looking up "IEEE 754" in Wikipedia. You can jump right to it with

http://en.wikipedia.org/wiki/IEEE_754#Double-precision_64_bit

, Nov 8, 2007
4. ### A. Sinan UnurGuest

wrote in news:1194534585.375896.109600

> #!/usr/local/bin/perl
>
> my \$i=2.55;
> \$i=\$i*100;
> print "\$i\n";
> my \$j=int(\$i);
> print "\$j\n";
>
> output:
> 255
> 254
>
> can someone explain that to me?

perldoc -q 999

#!/usr/bin/perl

my \$i = 2.55;
\$i = \$i * 100;
printf "%.0f\n", \$i;

__END__

--
A. Sinan Unur <>
(remove .invalid and reverse each component for email address)