Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

int(5800) == 5799 ? #961

Closed
p5pRT opened this issue Dec 16, 1999 · 3 comments
Closed

int(5800) == 5799 ? #961

p5pRT opened this issue Dec 16, 1999 · 3 comments

Comments

@p5pRT
Copy link

p5pRT commented Dec 16, 1999

Migrated from rt.perl.org#1908 (status was 'resolved')

Searchable as RT1908$

@p5pRT
Copy link
Author

p5pRT commented Dec 16, 1999

From mitchell@cs.leander.isd.tenet.edu

Given the following perl script, the int() function seems to generate the
wrong value.

#!/usr/bin/perl

  # int(5800) == 5799 ?

  $value = (( 29 / 50 ) * 100 ) * 100;
  $value2 = int $value;
  print "int($value) == $value2 ?\n";

#end of example script 1

The output is "int(5800) == 5799", which is not what I expect.

I've tried the script on two different machines, and the result is identical
on both.

The first machine is an AMD K6/2-350, running RedHat Linux 6.1​:

  % uname -a
  Linux hostname 2.2.5-15 #1 Mon Apr 19 22​:21​:09 EDT 1999 i586 unknown

  % perl --version
  This is perl, version 5.005_03 built for i386-linux

The second machine is a Pentium II - 400, running Windows 95 (retail)​:

  C​:\>ver
  Windows 95. [Version 4.00.950]

  C​:\>perl --version
  This is perl, version 5.005_02 built for MSWin32-x86-object
  (with 1 registered patch, see perl -V for more detail)

  Binary build 509 provided by ActiveState Tool Corp.
  Built 13​:37​:15 Jan 5 1999

As I said, both machines produce the unexpected output.

FWIW, running the code in a loop 0..50 shows that only the 29 is effected;
all other values produce the expected result.

#!/usr/bin/perl

  # only 29 is "incorrect"

  for $i ( 0..50 ) {
  $value = (( $i / 50 ) * 100 ) * 100;
  $value2 = int $value;
  print "int($value) == $value2 ?\n";
  }

#end of example script 2

Am I doing something wrong? If I'm making an incorrect assumption, I'd
appreciate a heads-up, and I'd prefer to fix things cleanly than hacking in a
fix like so​:

#!/usr/bin/perl

  # this produces the expected output

  $value = (( 29 / 50 ) * 100 ) * 100;
  $value2 = int ($value+0.01);
  print "int($value) == $value2 ?\n";

#end of example script 3

Anything you could tell me would be appreciated. Thanks in advance.

--
Graham Mitchell - Computer Science teacher, Leander HS

@p5pRT
Copy link
Author

p5pRT commented Dec 16, 1999

From @tamias

On Thu, Dec 16, 1999 at 04​:14​:51PM -0600, Graham Mitchell wrote​:

I'm beginning to wonder if I'm crazy. I've been programming long enough to
not blame the compiler when the code doesn't do what I expect, but this is a
stumper.

Given the following perl script, the int() function seems to generate the
wrong value.

#!/usr/bin/perl

\# int\(5800\) == 5799 ?

$value = \(\( 29 / 50 \) \* 100 \) \* 100;
$value2 = int $value;

perlfaq4 address this problem​:

  Why am I getting long decimals (eg, 19.9499999999999)
  instead of the numbers I should be getting (eg, 19.95)?

  The infinite set that a mathematician thinks of as the
  real numbers can only be approximate on a computer, since
  the computer only has a finite number of bits to store an
  infinite number of, um, numbers.

  Internally, your computer represents floating-point
  numbers in binary. Floating-point numbers read in from a
  file or appearing as literals in your program are
  converted from their decimal floating-point representation
  (eg, 19.95) to the internal binary representation.

  However, 19.95 can't be precisely represented as a binary
  floating-point number, just like 1/3 can't be exactly
  represented as a decimal floating-point number. The
  computer's binary representation of 19.95, therefore,
  isn't exactly 19.95.

  When a floating-point number gets printed, the binary
  floating-point representation is converted back to
  decimal. These decimal numbers are displayed in either
  the format you specify with printf(), or the current
  output format for numbers (see the section on $# in the
  perlvar manpage if you use print. $# has a different
  default value in Perl5 than it did in Perl4. Changing $#
  yourself is deprecated.

  This affects all computer languages that represent decimal
  floating-point numbers in binary, not just Perl. Perl
  provides arbitrary-precision decimal numbers with the
  Math​::BigFloat module (part of the standard Perl
  distribution), but mathematical operations are
  consequently slower.

  To get rid of the superfluous digits, just use a format
  (eg, printf("%.2f", 19.95)) to get the required precision.
  See the section on Floating-point Arithmetic in the perlop
  manpage.

The result of the floating point arithmetic in your script comes out to be
5799.9999999999991; when you truncate that with int(), you end up with
5799.

Ronald

@p5pRT
Copy link
Author

p5pRT commented Dec 17, 1999

From [Unknown Contact. See original ticket]

From​: Graham Mitchell [mailto​:mitchell@​cs.leander.isd.tenet.edu]

Given the following perl script, the int() function seems to
generate the
wrong value.

#!/usr/bin/perl

\# int\(5800\) == 5799 ?

$value = \(\( 29 / 50 \) \* 100 \) \* 100;
$value2 = int $value;
print "int\($value\) == $value2 ?\\n";

#end of example script 1

The output is "int(5800) == 5799", which is not what I expect.

The issue is that $value is actually 5799.99999999..., due to the use of
floating point (29/50 is float) and its inherent inaccuracies. Thus, $value2
is getting truncated to 5799.

But the print statement interpolates $value as a string, using the default
representation for floating point, which is rounded at (I think) 6 digits or
so. Hence, you see 5780. To see the lot, use printf​:

C​:\DATA>perl -e "printf '%%.20g', ((( 29 / 50 ) * 100 ) * 100)"
5799.9999999999991

Hope this helps,
Paul.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant