BrowserUk has asked for the wisdom of the Perl Monks concerning the following question:

Can anyone explain these outputs:

print +( 1<<(2**$_+$_-1) )-1 for 4,5,6;; 524287 68719476735 31 print unpack 'b*', pack 'Q', ( 1<<(2**$_+$_-1) )-1 for 4,5,6;; 1111111111111111111000000000000000000000000000000000000000000000 1111111111111111111111111111111111110000000000000000000000000000 1111100000000000000000000000000000000000000000000000000000000000

What I am expecting:

  1. 2^4 + 4 - 1 = 19
    1111111111111111111000000000000000000000000000000000000000000000
  2. 2^5 + 5 - 1 = 36
    1111111111111111111111111111111111110000000000000000000000000000
  3. 2^6 + 6 - 1 = 69
    1111111111111111111111111111111111111111111111111111111111111111

I know it can't be Perl's fault? But there it is...


With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority". I'm with torvalds on this
In the absence of evidence, opinion is indistinguishable from prejudice. Agile (and TDD) debunked

Replies are listed 'Best First'.
Re: Perl's bad at arithmetic?
by Eily (Monsignor) on Mar 27, 2015 at 23:29 UTC

    perlop says

    Note that both << and >> in Perl are implemented directly using << and >> in C
    [...]
    The result of overflowing the range of the integers is undefined because it is undefined also in C. In other words, using 32-bit integers, 1 << 32 is undefined. Shifting by a negative number of bits is also undefined.
    Not Perl's fault indeed.

    perl -E 'say unpack "b*", pack "Q", ( 3<<$_ ) for 60..70;' 0000000000000000000000000000000000000000000000000000000000001100 0000000000000000000000000000000000000000000000000000000000000110 0000000000000000000000000000000000000000000000000000000000000011 0000000000000000000000000000000000000000000000000000000000000001 1100000000000000000000000000000000000000000000000000000000000000 0110000000000000000000000000000000000000000000000000000000000000 0011000000000000000000000000000000000000000000000000000000000000 0001100000000000000000000000000000000000000000000000000000000000 0000110000000000000000000000000000000000000000000000000000000000 0000011000000000000000000000000000000000000000000000000000000000 0000001100000000000000000000000000000000000000000000000000000000

      But my shift value should be 19, 36 and 69 and I'm using a 64-bit perl, so, at worst, I should be having problems only with the last one.


      With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority". I'm with torvalds on this
      In the absence of evidence, opinion is indistinguishable from prejudice. Agile (and TDD) debunked

        I don't see anything wrong with the first two. Your output is actually the same as the expectations you provided.

Re: Perl's bad at arithmetic?
by roboticus (Chancellor) on Mar 27, 2015 at 23:31 UTC

    Yeah, that's certainly surprising. But when I looked in the docs (perldoc perlop) it says that:

    Note that both << and >> in Perl are implemented directly using << and >> in C. If use integer (see Integer Arithmetic) is in force then signed C integers are used, else unsigned C integers are used. Either way, the implementation isn't going to generate results larger than the size of the integer type Perl was built with (32 bits or 64 bits).

    The result of overflowing the range of the integers is undefined because it is undefined also in C. In other words, using 32-bit integers, 1 << 32 is undefined. Shifting by a negative number of bits is also undefined.

    If you get tired of being subject to your platform's native integers, the use bigint pragma neatly sidesteps the issue altogether:

    I was expecting that the 1 would shift off the end and leave you with all 0, rather than it wrapping back around.

    ...roboticus

    When your only tool is a hammer, all problems look like your thumb.

      Forget the shifts, look at the numbers: They should be 19, 36 & 69. (And on a 64-bit machine the first 2 should be fine for shifting a 64-bit int.)


      With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority". I'm with torvalds on this
      In the absence of evidence, opinion is indistinguishable from prejudice. Agile (and TDD) debunked

        BrowserUk:

        But the numbers look right (though backwards from the way I expect to see 'em). If you shift your 1 nineteen positions over and subtract one from the result, you'd get what you're showing you'd get. I don't see the issue with the first two.

        The last one, however looks like it rotated the 1 bit one end and onto the other.

        ...roboticus

        When your only tool is a hammer, all problems look like your thumb.