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

power-of two differences in minus operation #8859

Open
p5pRT opened this issue Mar 31, 2007 · 9 comments
Open

power-of two differences in minus operation #8859

p5pRT opened this issue Mar 31, 2007 · 9 comments

Comments

@p5pRT
Copy link

p5pRT commented Mar 31, 2007

Migrated from rt.perl.org#42260 (status was 'open')

Searchable as RT42260$

@p5pRT
Copy link
Author

p5pRT commented Mar 31, 2007

From jan-perl@h-i-s.nl

Created by jan-perl@h-i-s.nl

The minus operator creates strange results for the given example.
Using bignum or bigint does not change the results.
For the given program, running perl v5.6.1 on an old pentium-90 gave the
expected output in the last two colums​: the samen value as in the first
column, and zero respectively.
The example program reads a multiplier from the first line, and then
verifies the relation $val[4] == $val[0] * mult + $val[1]

example program​:

#!/usr/bin/perl -w

$mul=<STDIN>;
$mul+=0;
$hdrlin=<STDIN>;
  print "${mul}\n${hdrlin}";
while ($readlin = <STDIN> ) {
  @​vals =split(/\t/,$readlin);
  my $diff= ($vals[4] - $vals[1] ) - $vals[0]*$mul;
  my $v1m=sprintf ("%.0f",$vals[0]*$mul);
  my $v1c=sprintf ("%.0f",($vals[0]*$mul+$vals[1]));
  my $d1=sprintf ("%.0f", ($vals[4] - $vals[1] ) );
  print "$vals[0]\t$vals[1]\t$v1m\t$v1c\t$vals[4]\t$d1\t$diff\n";
}

example input​:

4294967296
v1 v2 v1m v1c v1g d1 diff
104712103 50 449735057880383488 449735057880383552 449735057880383538 0 -64
108391849 154 465539446607970304 465539446607970432
465539446607970458 192 64
108391849 159 465539446607970304 465539446607970432
465539446607970463 192 64
108391849 219 465539446607970304 465539446607970496
465539446607970523 256 64
112424657 21 482860225079017472 482860225079017472 482860225079017493 64 64
112424657 25 482860225079017472 482860225079017472 482860225079017497 64 64
113036199 53 485486777969147904 485486777969147968 485486777969147957 128 64
113036199 56 485486777969147904 485486777969147968 485486777969147960 128 64
114286490 102 490856736924631040 490856736924631168
490856736924631142 64 -64
114286490 105 490856736924631040 490856736924631168
490856736924631145 64 -64
114286490 108 490856736924631040 490856736924631168
490856736924631148 64 -64
114286490 114 490856736924631040 490856736924631168
490856736924631154 64 -64
114286490 98 490856736924631040 490856736924631168 490856736924631138 64 -64
116114550 207 498708194839756800 498708194839756992
498708194839757007 256 64
1454437274 498 6246760525913391104 6246760525913391104
6246760525913391602 1024 1024
1685221006 5 7237969107302219776 7237969107302219776
7237969107302219781 0 -1024
1689676942 5 7257107206695288832 7257107206695288832
7257107206695288837 0 1024

example output (WRONG, from given perl version)

4294967296
v1 v2 v1m v1c v1g d1 diff
104712103 50 449735057880383488 449735057880383552 449735057880383538
449735057880383424 -64
108391849 154 465539446607970304 465539446607970432
465539446607970458 465539446607970368 64
108391849 159 465539446607970304 465539446607970432
465539446607970463 465539446607970368 64
108391849 219 465539446607970304 465539446607970496
465539446607970523 465539446607970368 64
112424657 21 482860225079017472 482860225079017472 482860225079017493
482860225079017536 64
112424657 25 482860225079017472 482860225079017472 482860225079017497
482860225079017536 64
113036199 53 485486777969147904 485486777969147968 485486777969147957
485486777969147968 64
113036199 56 485486777969147904 485486777969147968 485486777969147960
485486777969147968 64
114286490 102 490856736924631040 490856736924631168
490856736924631142 490856736924630976 -64
114286490 105 490856736924631040 490856736924631168
490856736924631145 490856736924630976 -64
114286490 108 490856736924631040 490856736924631168
490856736924631148 490856736924630976 -64
114286490 114 490856736924631040 490856736924631168
490856736924631154 490856736924630976 -64
114286490 98 490856736924631040 490856736924631168 490856736924631138
490856736924630976 -64
116114550 207 498708194839756800 498708194839756992
498708194839757007 498708194839756864 64
1454437274 498 6246760525913391104 6246760525913391104
6246760525913391602 6246760525913392128 1024
1685221006 5 7237969107302219776 7237969107302219776
7237969107302219781 7237969107302218752 -1024
1689676942 5 7257107206695288832 7257107206695288832
7257107206695288837 7257107206695289856 1024

Correct output (as from the old perl on the old computer)

4294967296
v1 v2 v1m v1c v1g d1 diff
104712103 50 449735057880383488 449735057880383552 449735057880383538
449735057880383488 0
108391849 154 465539446607970304 465539446607970432
465539446607970458 465539446607970304 0
108391849 159 465539446607970304 465539446607970432
465539446607970463 465539446607970304 0
108391849 219 465539446607970304 465539446607970496
465539446607970523 465539446607970304 0
112424657 21 482860225079017472 482860225079017472 482860225079017493
482860225079017472 0
112424657 25 482860225079017472 482860225079017472 482860225079017497
482860225079017472 0
113036199 53 485486777969147904 485486777969147968 485486777969147957
485486777969147904 0
113036199 56 485486777969147904 485486777969147968 485486777969147960
485486777969147904 0
114286490 102 490856736924631040 490856736924631168
490856736924631142 490856736924631040 0
114286490 105 490856736924631040 490856736924631168
490856736924631145 490856736924631040 0
114286490 108 490856736924631040 490856736924631168
490856736924631148 490856736924631040 0
114286490 114 490856736924631040 490856736924631168
490856736924631154 490856736924631040 0
114286490 98 490856736924631040 490856736924631168 490856736924631138
490856736924631040 0
116114550 207 498708194839756800 498708194839756992
498708194839757007 498708194839756800 0
1454437274 498 6246760525913391104 6246760525913391104
6246760525913391602 6246760525913391104 0
1685221006 5 7237969107302219776 7237969107302219776
7237969107302219781 7237969107302219776 0
1689676942 5 7257107206695288832 7257107206695288832
7257107206695288837 7257107206695288832 0

Perl Info

Flags:
     category=core
     severity=high

Site configuration information for perl v5.8.8:

Configured by Debian Project at Fri Jul  7 18:20:22 UTC 2006.

Summary of my perl5 (revision 5 version 8 subversion 8) configuration:
   Platform:
     osname=linux, osvers=2.6.15.7, archname=i486-linux-gnu-thread-multi
     uname='linux rothera 2.6.15.7 #1 smp tue jun 27 18:34:43 utc 2006
i686 gnulinux '
     config_args='-Dusethreads -Duselargefiles -Dccflags=-DDEBIAN
-Dcccdlflags=-fPIC -Darchname=i486-linux-gnu -Dprefix=/usr
-Dprivlib=/usr/share/perl/5.8 -Darchlib=/usr/lib/perl/5.8
-Dvendorprefix=/usr -Dvendorlib=/usr/share/perl5
-Dvendorarch=/usr/lib/perl5 -Dsiteprefix=/usr/local
-Dsitelib=/usr/local/share/perl/5.8.8
-Dsitearch=/usr/local/lib/perl/5.8.8 -Dman1dir=/usr/share/man/man1
-Dman3dir=/usr/share/man/man3 -Dsiteman1dir=/usr/local/man/man1
-Dsiteman3dir=/usr/local/man/man3 -Dman1ext=1 -Dman3ext=3perl
-Dpager=/usr/bin/sensible-pager -Uafs -Ud_csh -Uusesfio -Uusenm
-Duseshrplib -Dlibperl=libperl.so.5.8.8 -Dd_dosuid -des'
     hint=recommended, useposix=true, d_sigaction=define
     usethreads=define use5005threads=undef useithreads=define
usemultiplicity=define
     useperlio=define d_sfio=undef uselargefiles=define usesocks=undef
     use64bitint=undef use64bitall=undef uselongdouble=undef
     usemymalloc=n, bincompat5005=undef
   Compiler:
     cc='cc', ccflags ='-D_REENTRANT -D_GNU_SOURCE -DTHREADS_HAVE_PIDS
-DDEBIAN -fno-strict-aliasing -pipe -I/usr/local/include
-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64',
     optimize='-O2',
     cppflags='-D_REENTRANT -D_GNU_SOURCE -DTHREADS_HAVE_PIDS -DDEBIAN
-fno-strict-aliasing -pipe -I/usr/local/include'
     ccversion='', gccversion='4.1.2 20060613 (prerelease) (Ubuntu
4.1.1-2ubuntu5)', gccosandvers=''
     intsize=4, longsize=4, ptrsize=4, doublesize=8, byteorder=1234
     d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=12
     ivtype='long', ivsize=4, nvtype='double', nvsize=8, Off_t='off_t',
lseeksize=8
     alignbytes=4, prototype=define
   Linker and Libraries:
     ld='cc', ldflags =' -L/usr/local/lib'
     libpth=/usr/local/lib /lib /usr/lib
     libs=-lgdbm -lgdbm_compat -ldb -ldl -lm -lpthread -lc -lcrypt
     perllibs=-ldl -lm -lpthread -lc -lcrypt
     libc=/lib/libc-2.4.so, so=so, useshrplib=true, libperl=libperl.so.5.8.8
     gnulibc_version='2.4'
   Dynamic Linking:
     dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-Wl,-E'
     cccdlflags='-fPIC', lddlflags='-shared -L/usr/local/lib'

Locally applied patches:



@INC for perl v5.8.8:
     /etc/perl
     /usr/local/lib/perl/5.8.8
     /usr/local/share/perl/5.8.8
     /usr/lib/perl5
     /usr/share/perl5
     /usr/lib/perl/5.8
     /usr/share/perl/5.8
     /usr/local/lib/site_perl
     .


Environment for perl v5.8.8:
     HOME=/home/jhh
     LANG=en_US.UTF-8
     LANGUAGE=en_NL:en
     LD_LIBRARY_PATH (unset)
     LOGDIR (unset)

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/bin/X11:/usr/games
     PERL_BADLANG (unset)
     SHELL=/bin/bash


@p5pRT
Copy link
Author

p5pRT commented Apr 9, 2007

From @doughera88

On Sat, 31 Mar 2007, jhh wrote​:

# New Ticket Created by jhh
# Please include the string​: [perl #42260]
# in the subject line of all future correspondence about this issue.
# <URL​: http​://rt.perl.org/rt3/Ticket/Display.html?id=42260 >

The minus operator creates strange results for the given example.

Here's a much shorter example that illustrates the same problem.
What you are encountering is the finite resolution of perl's (and C's)
floating point numbers. If you really require 18-digit accuracy, then
perl's built-in numbers are not the right tool.

You are correct that the exact details of rounding off in the last
bit have changed between 5.6 and 5.8, but in neither version should they
have been considered reliable.

Using bignum or bigint does not change the results.

That's odd. You'll have to show us specifically what you're doing.
It's probably best if you modify the program below and show what you
expect and what you get. BigInt should work.

#!/usr/bin/perl -w
my $mul = 2**32;
my $a = 104712103;
my $b = 50;
my $c = 449735057880383538;
# For these values, $mul * $a + $b == $c. Thus $diff should be zero.
my $diff = $c - ($a * $mul + $b);
printf "Expected​: $a $b 449735057880383538 0\n";
printf "Got​: %.0f %.0f %.0f %.0f\n", $a, $b, $c, $diff;

__END__

# Actual output (Solaris/SPARC, 32-bit integers)​:

$ perl5.6.2 bugreport
Expected​: 104712103 50 449735057880383538 0
Got​: 104712103 50 449735057880383552 0

$ perl5.8.8 bugreport
Expected​: 104712103 50 449735057880383538 0
Got​: 104712103 50 449735057880383488 -64

Note too that for both 5.6 and 5.8, the value of $c rendered by
printf "%.0f" is wrong.

--
  Andy Dougherty doughera@​lafayette.edu

@p5pRT
Copy link
Author

p5pRT commented Apr 9, 2007

The RT System itself - Status changed from 'new' to 'open'

@p5pRT
Copy link
Author

p5pRT commented Apr 9, 2007

From @doughera88

On Mon, 9 Apr 2007, Tels wrote​:

-----BEGIN PGP SIGNED MESSAGE-----
Hash​: SHA1

Moin,

On Monday 09 April 2007 19​:00​:56 Andy Dougherty wrote​:

On Sat, 31 Mar 2007, jhh wrote​:

Using bignum or bigint does not change the results.

That's odd. You'll have to show us specifically what you're doing.
It's probably best if you modify the program below and show what you
expect and what you get. BigInt should work.

When using "-Mbignum", the diff will be zero, but the printout of $c will be
wrong since %0.f is used, which converts the BigInt to a normal floating
point value before printing, thus losing bits​:

Yes. I agree. That's why I said the original poster would have to
show us specifically what he was doing.

You are also correct that the wrong number is still printed by
printf("%.0f"). However, the wrong number also was printed with perl5.6
and that apparently wasn't an important issue for the original poster.
(Why it didn't matter, I don't know, but then I don't know the full
context of the original problem.)

--
  Andy Dougherty doughera@​lafayette.edu

@p5pRT
Copy link
Author

p5pRT commented Apr 9, 2007

From nospam-abuse@bloodgate.com

-----BEGIN PGP SIGNED MESSAGE-----
Hash​: SHA1

Moin,

On Monday 09 April 2007 19​:00​:56 Andy Dougherty wrote​:

On Sat, 31 Mar 2007, jhh wrote​:

# New Ticket Created by jhh
# Please include the string​: [perl #42260]
# in the subject line of all future correspondence about this issue.
# <URL​: http​://rt.perl.org/rt3/Ticket/Display.html?id=42260 >

The minus operator creates strange results for the given example.

Here's a much shorter example that illustrates the same problem.
What you are encountering is the finite resolution of perl's (and C's)
floating point numbers. If you really require 18-digit accuracy, then
perl's built-in numbers are not the right tool.

You are correct that the exact details of rounding off in the last
bit have changed between 5.6 and 5.8, but in neither version should they
have been considered reliable.

Using bignum or bigint does not change the results.

That's odd. You'll have to show us specifically what you're doing.
It's probably best if you modify the program below and show what you
expect and what you get. BigInt should work.

When using "-Mbignum", the diff will be zero, but the printout of $c will be
wrong since %0.f is used, which converts the BigInt to a normal floating
point value before printing, thus losing bits​:

  #!/usr/bin/perl -w
  my $mul = 2**32;
  my $a = 104712103;
  my $b = 50;
  my $c = 449735057880383538;
  # For these values, $mul * $a + $b == $c.  Thus $diff should be zero.
  my $diff = $c - ($a * $mul + $b);
  printf "Expected​: $a $b 449735057880383538 0\n";
  printf "Got​:      %.0f %.0f %.0f %.0f\n", $a, $b, $c, $diff;
  printf "\$c $c %0.f\n", $c;

Result (5.8.8 on 64bit, thus diff is 0 even without bignum)​:

  # perl acc.pl
  Expected​: 104712103 50 449735057880383538 0
  Got​:      104712103 50 449735057880383552 0
  $c 449735057880383538 449735057880383552
  # perl -Mbignum acc.pl
  Expected​: 104712103 50 449735057880383538 0
  Got​:      104712103 50 449735057880383552 0
  $c 449735057880383538 449735057880383552

I am not sure if printf("%0.f", $bignumber) should actually truncate the
result, or just print it in all its glory. Can this even be achieved with
overloading?

All the best,

Tels

- --
Signed on Mon Apr 9 21​:11​:42 2007 with key 0x93B84C15.
View my photo gallery​: http​://bloodgate.com/photos
PGP key on http​://bloodgate.com/tels.asc or per email.

"The need for a Steam account to play HL2 is like having to login to MS
Passport to play Minesweeper."

  -- Tels
-----BEGIN PGP SIGNATURE-----
Version​: GnuPG v1.4.2 (GNU/Linux)

iQEVAwUBRhqtJHcLPEOTuEwVAQIJhQf7BPTehno/agg+Qzw1tQkdL/dXFKLuwXby
PLggxcjanVjn4q3w5rg+FiJURPONQAOHPPgR8i8aYMYnXHd+WfsK4raVi2AGw7LL
jKOhyLwQBywNGvWhrEn8LFvid69CKIkIBUorLuj4i0NaxFAhoC8tKg3/fFxt6z5u
woMwdeUuMfBPi8iwOW+5GlVvYpQSp19WdflSaQhjv5LBFV2MdtnpYNiqX41DpzNt
H3KmhF3gZyD5R5CJvLYeQj+OrVjAWSjJ/pUoevJBlLU6O9EB1ujx6HLK6lV13zaU
fryvoNSQQpdiqM2ggGreccvPjyd7paAIO3e003sh8E2/k/sjE/xOpA==
=+9+y
-----END PGP SIGNATURE-----

@p5pRT
Copy link
Author

p5pRT commented Apr 10, 2007

From jan-perl@h-i-s.nl

What I really am trying to do is to verify the numbers are right​:
it is output of an embedded software system running on another computer
platform.
Thus, the only real issue for me is if the $diff variable actually goes
to zero, as it did in the older versions.

I did now check with bignum on, and actually get larger diffs
-- perl -Mbignum ./chk2.pl <prcmult3.txt >prcmult8bn.txt

I am not familiar enough with perl to change operator overloading etc.
I am familiar with C and data types, however.
I suspect that forcing the reading routine to generate 64 bit integers
would allow the reproduction of the results of your code examples.

4294967296
v1 v2 v1m v1c v1g d1 diff
104712103 50 449735057880383488 449735057880383552 449735057880383538
449735057880383424 -488
108391849 154 465539446607970304 465539446607970432
465539446607970458 465539446607970368 -304
108391849 159 465539446607970304 465539446607970432
465539446607970463 465539446607970368 -304
108391849 219 465539446607970304 465539446607970496
465539446607970523 465539446607970368 -304
112424657 21 482860225079017472 482860225079017472 482860225079017493
482860225079017536 528
112424657 25 482860225079017472 482860225079017472 482860225079017497
482860225079017536 528
113036199 53 485486777969147904 485486777969147968 485486777969147957
485486777969147968 96
113036199 56 485486777969147904 485486777969147968 485486777969147960
485486777969147968 96
114286490 102 490856736924631040 490856736924631168
490856736924631142 490856736924630976 -40
114286490 105 490856736924631040 490856736924631168
490856736924631145 490856736924630976 -40
114286490 108 490856736924631040 490856736924631168
490856736924631148 490856736924630976 -40
114286490 114 490856736924631040 490856736924631168
490856736924631154 490856736924630976 -40
114286490 98 490856736924631040 490856736924631168 490856736924631138
490856736924630976 -40
116114550 207 498708194839756800 498708194839756992
498708194839757007 498708194839756864 200
1454437274 498 6246760525913391104 6246760525913391104
6246760525913391602 6246760525913392128 -1104
1685221006 5 7237969107302219776 7237969107302219776
7237969107302219781 7237969107302218752 224
1689676942 5 7257107206695288832 7257107206695288832
7257107206695288837 7257107206695289856 1168

@p5pRT
Copy link
Author

p5pRT commented Apr 10, 2007

From jan-perl@h-i-s.nl

I have posted a follow-up via the bug-tracking tool.
I hope you get an update that way.

--
Jan Hoogenraad
Hoogenraad Interface Services
Postbus 2717
3500 GS Utrecht

@p5pRT
Copy link
Author

p5pRT commented Jul 16, 2016

From @dcollinsn

Is there any more to this ticket than "floats have limited precision"? There's some discussion about printf('%f') under Bignum, but my understanding is that the %f format specifier is supposed to treat the input as a float.

--
Respectfully,
Dan Collins

@p5pRT
Copy link
Author

p5pRT commented Jul 16, 2016

From @sisyphus

-----Original Message-----
From​: Dan Collins via RT
Sent​: Saturday, July 16, 2016 12​:56 PM
To​: OtherRecipients of perl Ticket #42260​:
Cc​: perl5-porters@​perl.org
Subject​: [perl #42260] power-of two differences in minus operation

Is there any more to this ticket than "floats have limited precision"?
There's some discussion about printf('%f') under Bignum, but my
understanding is that the %f format specifier is supposed to treat the
input as a float.

I think this crosses over into #41202 territory.

I find that perl is assigning 449735057880383538 incorrectly - to internal
hex format of 4398f71e9c000000 (instead of 4398f71e9c000001).
And I think that's happening to the op as well.

For the script​:

my $mul = 2**32; my $a = 104712103; my $b = 50;
my $c = 449735057880383538; # For these values, $mul * $a + $b == $c. Thus
$diff should be zero.
my $diff = $c - ($a * $mul + $b);
printf "Expected​: $a $b 449735057880383538 0\n";
printf "Got​: %.0f %.0f %.0f %.0f\n", $a, $b, $c, $diff;
printf "\$c $c %0.f\n", $c;

I get outputs of (perl-5.16.0)​:

Expected​: 104712103 50 449735057880383538 0
Got​: 104712103 50 449735057880383488 -64
$c 4.49735057880383e+017 449735057880383488

and (perl-5.24.0)​:

Expected​: 104712103 50 449735057880383538 0
Got​: 104712103 50 449735057880383552 0
$c 449735057880383538 449735057880383550

In both of those perls "my $c = 449735057880383538;" has assigned
4398f71e9c000000 to $c.

Cheers,
Rob

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

2 participants