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

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

Thread Previous
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

Thread Previous


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About