Front page | perl.perl5.porters | Postings from May 2008

## [perl #53784] 64-bit Integers -- inexact division gives odd result when is large

From:
Chris Hall
Date:
May 7, 2008 03:11
Subject:
[perl #53784] 64-bit Integers -- inexact division gives odd result when is large
Message ID:
```# New Ticket Created by  Chris Hall
# Please include the string:  [perl #53784]
# <URL: http://rt.perl.org/rt3/Ticket/Display.html?id=53784 >

This is a bug report for perl from chris.hall@highwayman.com,
generated with the help of perlbug 1.35 running under perl v5.8.8.

-----------------------------------------------------------------

Division of a large 64-bit integer by a small integer gives peculiar
(broken) result when the division is inexact.

Consider:

idiv(0x0FED_CBA9_8765_4321, 9, 9) ;

print "_" x 70, "\n" ;

idiv(1<<52, 3, 2) ;

sub idiv {
my (\$z, \$j, \$b) = @_ ;

printf "a =  0x%016X * \$b + i, for i = 0..%d\n", \$z, \$j ;
print "  i:    d = int(a/\$b)    :        a/\$b           :",
" a%\$b : a - d*\$b\n" ;

foreach my \$i (0..\$j) {
my \$a = (\$z * \$b) + \$i ;
my \$q = \$a / \$b ;
my \$d = int(\$q) ;
my \$r = \$a % \$b ;
my \$s = \$a - (\$d * \$b) ;

printf " %2d: 0x%016X : %20s : %+3d : %+5d\n", \$i, \$d, "\$q", \$r, \$s ;
} ;
} ;

which on an x86-64 produces:

a =  0x0FEDCBA987654321 * 9 + i, for i = 0..9
i:    d = int(a/9)    :        a/9           : a%9 : a - d*9
0: 0x0FEDCBA987654321 :  1147797409030816545 :  +0 :    +0
1: 0x0FEDCBA987654380 : 1.14779740903082e+18 :  +1 :  -854
2: 0x0FEDCBA987654380 : 1.14779740903082e+18 :  +2 :  -853
3: 0x0FEDCBA987654380 : 1.14779740903082e+18 :  +3 :  -852
4: 0x0FEDCBA987654380 : 1.14779740903082e+18 :  +4 :  -851
5: 0x0FEDCBA987654380 : 1.14779740903082e+18 :  +5 :  -850
6: 0x0FEDCBA987654380 : 1.14779740903082e+18 :  +6 :  -849
7: 0x0FEDCBA987654380 : 1.14779740903082e+18 :  +7 :  -848
8: 0x0FEDCBA987654380 : 1.14779740903082e+18 :  +8 :  -847
9: 0x0FEDCBA987654322 :  1147797409030816546 :  +0 :    +0
______________________________________________________________________
a =  0x0010000000000000 * 2 + i, for i = 0..3
i:    d = int(a/2)    :        a/2           : a%2 : a - d*2
0: 0x0010000000000000 :     4503599627370496 :  +0 :    +0
1: 0x0010000000000000 :     4503599627370496 :  +1 :    +1
2: 0x0010000000000001 :     4503599627370497 :  +0 :    +0
3: 0x0010000000000002 :     4503599627370498 :  +1 :    -1

The first section shows the effect.  Where the integer division is exact we
get the right integer result.  Where it is not exact, the result is floated,
with hopeless loss of significance !

I assume that the code runs an integer division, and when the remainder is
not zero it floats the result of the division and then adds
remainder / divisor.

The second section shows what happens when the result of the division is
53 bits of integer (same as precision of the floating point), plus fraction
when the result is not exact.  Note the effect of Round-to-Even !

I suggest that the code should be extended to check if the result is
>= max integer in floating form.  If it is, then the result should be left
in integer form, and: if remainder is > divisor/2 round up, or
if remainder == divisor/2, round to even.

(As shown above, the % operator is giving the right result.  So all is
not lost.)

[FWIW: Round-to-Even is all very well, but in this case truncation would
seem a better choice -- all inexact integer divisions would then
always yield the integer result + fraction (when precision allows).]

[Please do not change anything below this line]
-----------------------------------------------------------------
---
Flags:
category=core
severity=high
---
This perlbug was built using Perl v5.8.8 in the Red Hat build system.
It is being executed now by Perl v5.8.8 - Thu Mar 20 04:50:07 EDT 2008.

Site configuration information for perl v5.8.8:

Configured by Red Hat, Inc. at Thu Mar 20 04:50:07 EDT 2008.

Summary of my perl5 (revision 5 version 8 subversion 8) configuration:
Platform:
uname='linux xenbuilder2.fedora.redhat.com 2.6.18-53.1.6.el5xen #1 smp wed jan 16 04:10:44 est 2008 x86_64 x86_64 x86_64 gnulinux '
config_args='-des -Doptimize=-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m64 -
mtune=generic -Dversion=5.8.8 -Dmyhostname=localhost -Dperladmin=root@localhost -Dcc=gcc -Dcf_by=Red Hat, Inc. -Dinstallprefix=/usr -
Dprefix=/usr -Dlibpth=/usr/local/lib64 /lib64 /usr/lib64 -Dprivlib=/usr/lib/perl5/5.8.8 -Dsitelib=/usr/lib/perl5/site_perl/5.8.8 -Dvendorlib=/us
Di_syslog -Dman3ext=3pm -Duseperlio -Dinstallusrbinperl=n -Ubincompat5005 -Uversiononly -Dpager=/usr/bin/less -isr -Dd_gethostent_r_proto -
Ud_endhostent_r_proto -Ud_sethostent_r_proto -Ud_endprotoent_r_proto -Ud_setprotoent_r_proto -Ud_endservent_r_proto -Ud_setservent_r_proto -
Dinc_version_list=5.8.7 5.8.6 5.8.5 -Dscriptdir=/usr/bin'
hint=recommended, useposix=true, d_sigaction=define
useperlio=define d_sfio=undef uselargefiles=define usesocks=undef
use64bitint=define use64bitall=define uselongdouble=undef
usemymalloc=n, bincompat5005=undef
Compiler:
cc='gcc', ccflags ='-D_REENTRANT -D_GNU_SOURCE -fno-strict-aliasing -pipe -Wdeclaration-after-statement -I/usr/local/include -
D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -I/usr/include/gdbm',
optimize='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m64 -mtune=generic',
cppflags='-D_REENTRANT -D_GNU_SOURCE -fno-strict-aliasing -pipe -Wdeclaration-after-statement -I/usr/local/include -I/usr/include/gdbm'
ccversion='', gccversion='4.1.2 20070925 (Red Hat 4.1.2-33)', gccosandvers=''
intsize=4, longsize=8, ptrsize=8, doublesize=8, byteorder=12345678
d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=16
ivtype='long', ivsize=8, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8
alignbytes=8, prototype=define
ld='gcc', ldflags =''
libpth=/usr/local/lib64 /lib64 /usr/lib64
libs=-lresolv -lnsl -lgdbm -ldb -ldl -lm -lcrypt -lutil -lpthread -lc
perllibs=-lresolv -lnsl -ldl -lm -lcrypt -lutil -lpthread -lc
libc=, so=so, useshrplib=true, libperl=libperl.so
gnulibc_version='2.7'
cccdlflags='-fPIC', lddlflags='-shared -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -
m64 -mtune=generic'

Locally applied patches:

---
@INC for perl v5.8.8:
/usr/lib/perl5/site_perl/5.8.8
/usr/lib/perl5/site_perl/5.8.7
/usr/lib/perl5/site_perl/5.8.6
/usr/lib/perl5/site_perl/5.8.5
/usr/lib/perl5/site_perl
/usr/lib/perl5/vendor_perl/5.8.8
/usr/lib/perl5/vendor_perl/5.8.7
/usr/lib/perl5/vendor_perl/5.8.6
/usr/lib/perl5/vendor_perl/5.8.5
/usr/lib/perl5/vendor_perl
/usr/lib/perl5/5.8.8
.

---
Environment for perl v5.8.8:
HOME=/home/GMCH
LANG=en_GB.UTF-8
LANGUAGE (unset)
LD_LIBRARY_PATH (unset)
LOGDIR (unset)
PATH=/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin