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

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

From:
Chris Hall
Date:
May 7, 2008 08:33
Subject:
Re: [perl #53784] 64-bit Integers -- inexact division gives odd result when is large
Message ID:
necNNcgn+bIIFwv3@agrotera.halldom.com
```On Wed, 7 May 2008 you wrote
>On 2008–05–06, at 19:58, Chris Hall (via RT) wrote:
>
>Good news -- from the point of view of repeatability: I get the same
>results as you when running your test program on a 64-bit blead perl
>(patchlevel 33783).

>> 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 !

>Bad news from the point of view of understanding the phenomenon: I get
>the same results as you when I put -Minteger on the 64-bit perl
>command line; that is, when arithmetic operations are carried out with
>machine integers and fractional parts are truncated. Same if I put -
>Mbigint, replacing all machine arithmetic with arbitrary precision
>integer operations.
>
>These modules appear to be behaving themselves:
>
>domo:64-bit_perl-current\$ ./perl -lwe '\$x=2**60 + 3; print \$x/2 - 2**59'
>0

Documentation says that 2**n is a floating value.  So you'll find that:

\$ perl -lwe '\$x=2**63 + 27; print \$x - 2**63'
0

More interesting is:

\$ perl -lwe '\$x=(1<<62) + 27; print \$x - (1<<62)'
27

\$ perl -lwe '\$x=(1<<62) + 27; print \$x/2 - (1<<61)'
0

but when the division is exact:

\$ perl -lwe '\$x=(1<<62) + 26; print \$x/2 - (1<<61)'
13

When \$x = 2**62 + 27, \$x/2 is 2**61 + 13.5 -- forcing that to floating
point introduces a bigger error than rounding to 64-bit integer.

>domo:64-bit_perl-current\$ ./perl -Ilib -Minteger -lwe '\$x=2**60 + 3;
>print \$x/2 - 2**59'
>1

umm... this is different from the result when \$x/2 is pushed into
floating form... which is what one would expect.

With -Minteger 2**n is clearly an integer:

\$ perl -Ilib -Minteger -lwe '\$x=(2**62) + 27; print \$x - (2**62)'
27

And, since division now truncates:

\$ perl -Ilib -Minteger -lwe '\$x=(2**62) + 27; print \$x/2 - (2**61)'
13

>domo:64-bit_perl-current\$ ./perl -Ilib -Mbigint -lwe '\$x=2**60 + 3;
>print \$x/2 - 2**59'
>1

Similarly:

\$ perl -Ilib -Mbigint -lwe '\$x=(2**62) + 27; print \$x/2 - (2**61)'
13

Is the same as -Minteger, but different from the default case.

>Can you say why I should be getting the same results from your test
>program in all three cases?

Not really.  If I run my test with -Minteger, I get:

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: 0x0FEDCBA987654321 :  1147797409030816545 :  +1 :   +1
2: 0x0FEDCBA987654321 :  1147797409030816545 :  +2 :   +2
3: 0x0FEDCBA987654321 :  1147797409030816545 :  +3 :   +3
4: 0x0FEDCBA987654321 :  1147797409030816545 :  +4 :   +4
5: 0x0FEDCBA987654321 :  1147797409030816545 :  +5 :   +5
6: 0x0FEDCBA987654321 :  1147797409030816545 :  +6 :   +6
7: 0x0FEDCBA987654321 :  1147797409030816545 :  +7 :   +7
8: 0x0FEDCBA987654321 :  1147797409030816545 :  +8 :   +8
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: 0x0010000000000001 :     4503599627370497 :  +1 :   +1

which is what you'd expect for truncating integer division...

...and not the same as the default case, where the division is rounded
into floating point:

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  <<< !!

Are you getting something else ?

Chris
--
Chris Hall               highwayman.com

```