Different bitwise operation results on different machines

3

I'm implementing a simple bit rotation in PHP using this code:

(($n>>1)&0xFFFFFFFF)|(($n&0x00000001)<<31)

When I run this code on different machines, I get completely different results. At first I thought it had something to do with endianness but they're both x86, I'm just using different versions of PHP.

What's causing this behavior?

Edit: nevermind my previous example, it was incorrect

php
bit-manipulation
bitwise-operators
bit-shift
asked on Stack Overflow Feb 14, 2019 by dosse91214 • edited Feb 14, 2019 by dosse91214

3 Answers

0

The problem is definitely caused by PHP_INT_SIZE being 4 and not 8

answered on Stack Overflow Feb 14, 2019 by dosse91214
0

PHP 5.5 and 5.6 on x86-64 windows is experimental and uses 32 bit arithmetic. There aren't any ways around this so you just need to take into consideration that word size may vary from 4 to 8 bytes even across the same architecture.

answered on Stack Overflow Feb 14, 2019 by Prodigle
0

You can examine here step by step. I did a little 3v4l.org script

I illustrated two bit rotations: 1st for 2147483647, 2nd for 2147483648 1st is the max 32 bit number, 2nd is one more

See: PHP: integers -Manual # Integer overflow

You can see, the output is the same for every PHP version from 4.3.0 upwards

Here's the code:

<?php

$n = 2147483647;
shift($n);
echo "\n";
echo "\n";
echo "\n";
echo "\n";
$n = 2147483648;
shift($n);

function out($a, $b, $c, $b2 = '0', $c1 = ' ') {
    $padstra = 40;
    $padstrb = 23;
    echo 
        str_pad($a, $padstra, ' ', STR_PAD_LEFT) 
      . " " 
      . str_pad(decbin($b), 32, $b2, STR_PAD_LEFT) 
      . " " 
      . str_pad($c, $padstrb, $c1) . "\n";
}

function shift($n) {
    out($n    , $n , '$n'   );
    echo "\n";
    out('A:', $n >> 1 , '$n >> 1'   );
    out('B:', 0xFFFFFFFF , '0xFFFFFFFF'   );
    out('A & B:', ($n >> 1) & 0xFFFFFFFF , '($n >> 1) & 0xFFFFFFFF'   );
    echo "\n";
    out('C:', $n , '$n'   );
    out('D:', 0x00000001 , '0x00000001'   );
    out('C & D:', $n & 0x00000001 , '$n & 0x00000001'   );
    echo "\n";
    out('C & D:', $n & 0x00000001 , '$n & 0x00000001'   );
    out('(C & D) << 31:', ($n & 0x00000001) << 31 , '($n & 0x00000001) << 31'   );
    echo "\n";
    out('A & B:', ($n >> 1) & 0xFFFFFFFF , '($n >> 1) & 0xFFFFFFFF'   );
    out('(C & D) << 31:', ($n & 0x00000001) << 31 , '($n & 0x00000001) << 31'   );
    out('(A & B) | ((C & D) << 31):', ($n >> 1) & 0xFFFFFFFF | ($n & 0x00000001) << 31 , '($n >> 1) & 0xFFFFFFFF | ($n & 0x00000001) << 31');
}

Here's the output

                      2147483647 01111111111111111111111111111111 $n                     

                              A: 00111111111111111111111111111111 $n >> 1                
                              B: 11111111111111111111111111111111 0xFFFFFFFF             
                          A & B: 00111111111111111111111111111111 ($n >> 1) & 0xFFFFFFFF 

                              C: 01111111111111111111111111111111 $n                     
                              D: 00000000000000000000000000000001 0x00000001             
                          C & D: 00000000000000000000000000000001 $n & 0x00000001        

                          C & D: 00000000000000000000000000000001 $n & 0x00000001        
                  (C & D) << 31: 10000000000000000000000000000000 ($n & 0x00000001) << 31

                          A & B: 00111111111111111111111111111111 ($n >> 1) & 0xFFFFFFFF 
                  (C & D) << 31: 10000000000000000000000000000000 ($n & 0x00000001) << 31
      (A & B) | ((C & D) << 31): 10111111111111111111111111111111 ($n >> 1) & 0xFFFFFFFF | ($n & 0x00000001) << 31




                      2147483648 10000000000000000000000000000000 $n                     

                              A: 01000000000000000000000000000000 $n >> 1                
                              B: 11111111111111111111111111111111 0xFFFFFFFF             
                          A & B: 01000000000000000000000000000000 ($n >> 1) & 0xFFFFFFFF 

                              C: 10000000000000000000000000000000 $n                     
                              D: 00000000000000000000000000000001 0x00000001             
                          C & D: 00000000000000000000000000000000 $n & 0x00000001        

                          C & D: 00000000000000000000000000000000 $n & 0x00000001        
                  (C & D) << 31: 00000000000000000000000000000000 ($n & 0x00000001) << 31

                          A & B: 01000000000000000000000000000000 ($n >> 1) & 0xFFFFFFFF 
                  (C & D) << 31: 00000000000000000000000000000000 ($n & 0x00000001) << 31
      (A & B) | ((C & D) << 31): 01000000000000000000000000000000 ($n >> 1) & 0xFFFFFFFF | ($n & 0x00000001) << 31
answered on Stack Overflow Feb 14, 2019 by yunzen • edited Feb 14, 2019 by yunzen

User contributions licensed under CC BY-SA 3.0