470,821 Members | 1,959 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 470,821 developers. It's quick & easy.

confusing >> results

Using >> normally shifts bits to the right x number of times, where x
is specified by the programmer. As an example, 0x40000000 >> 8 yields
0x00400000. This makes me wonder... why doesn't the same thing happen
with 0x80000000 >> 8? The number it yields is 0xff800000 - not
0x00800000. The following script better demonstrates this:

<?
echo sprintf('%08x',0x40000000 >> 8)."\n";
echo sprintf('%08x',0x80000000 >> 8);
?>

Anyway, any ideas?

Jan 16 '06 #1
12 1466
yawnmoth wrote:
Using >> normally shifts bits to the right x number of times, where x
is specified by the programmer. As an example, 0x40000000 >> 8 yields
0x00400000. This makes me wonder... why doesn't the same thing happen
with 0x80000000 >> 8? The number it yields is 0xff800000 - not
0x00800000. The following script better demonstrates this:

<?
echo sprintf('%08x',0x40000000 >> 8)."\n";
echo sprintf('%08x',0x80000000 >> 8);
?>

Anyway, any ideas?


My guess is that PHP sees 0x8000000 as a *signed* integer
Jan 16 '06 #2
Palle Hansen wrote:
yawnmoth wrote:
Using >> normally shifts bits to the right x number of times, where x
is specified by the programmer. As an example, 0x40000000 >> 8 yields
0x00400000. This makes me wonder... why doesn't the same thing happen
with 0x80000000 >> 8? The number it yields is 0xff800000 - not
0x00800000. The following script better demonstrates this:

<?
echo sprintf('%08x',0x40000000 >> 8)."\n";
echo sprintf('%08x',0x80000000 >> 8);
?>

Anyway, any ideas?


My guess is that PHP sees 0x8000000 as a *signed* integer


Seems like you're right, Palle.

I tested with this code:

<?php
header('Content-Type: text/plain');

$t = 0x80000000;
echo $t-1, '; ', $t, '; ', $t + 1, "\n";
var_dump($t);

/*********
* <quote src="http://www.php.net/unpack">
* CAUTION
* Note that PHP internally stores integral values as signed. If
* you unpack a large unsigned long and it is of the same size as
* PHP internally stored values the result will be a negative
* number even though unsigned unpacking was specified.
* </quote>
*********/

/* N: unsigned long (always 32 bit, big endian byte order) */
$unsignedlong = unpack('N', "\x80\x00\x00\x00");
var_dump($unsignedlong);
?>
--
Mail to my "From:" address is readable by all at http://www.dodgeit.com/
== ** ## !! ------------------------------------------------ !! ## ** ==
TEXT-ONLY mail to the whole "Reply-To:" address ("My Name" <my@address>)
may bypass my spam filter. If it does, I may reply from another address!
Jan 16 '06 #3

Palle Hansen wrote:
yawnmoth wrote:
Using >> normally shifts bits to the right x number of times, where x
is specified by the programmer. As an example, 0x40000000 >> 8 yields
0x00400000. This makes me wonder... why doesn't the same thing happen
with 0x80000000 >> 8? The number it yields is 0xff800000 - not
0x00800000. The following script better demonstrates this:

<?
echo sprintf('%08x',0x40000000 >> 8)."\n";
echo sprintf('%08x',0x80000000 >> 8);
?>

Anyway, any ideas?


My guess is that PHP sees 0x8000000 as a *signed* integer


Why should >> even be concerned with whether or not integers are signed?

Jan 16 '06 #4
Palle Hansen wrote:
yawnmoth wrote:
Using >> normally shifts bits to the right x number of times, where x
is specified by the programmer. As an example, 0x40000000 >> 8 yields
0x00400000. This makes me wonder... why doesn't the same thing happen
with 0x80000000 >> 8? The number it yields is 0xff800000 - not
0x00800000. The following script better demonstrates this:

<?
echo sprintf('%08x',0x40000000 >> 8)."\n";
echo sprintf('%08x',0x80000000 >> 8);
?>

Anyway, any ideas?


My guess is that PHP sees 0x8000000 as a *signed* integer


No, PHP sees 0x80000000 as a double, because the number is beyond the
range of an integer (on 32 bit systems).

Jan 16 '06 #5
Chung Leong wrote:
Palle Hansen wrote:
yawnmoth wrote:
Using >> normally shifts bits to the right x number of times, where x
is specified by the programmer. As an example, 0x40000000 >> 8 yields
0x00400000. This makes me wonder... why doesn't the same thing happen
with 0x80000000 >> 8? The number it yields is 0xff800000 - not
0x00800000. The following script better demonstrates this:

<?
echo sprintf('%08x',0x40000000 >> 8)."\n";
echo sprintf('%08x',0x80000000 >> 8);
?>

Anyway, any ideas?


My guess is that PHP sees 0x8000000 as a *signed* integer

No, PHP sees 0x80000000 as a double, because the number is beyond the
range of an integer (on 32 bit systems).


No, 0x80000000 is exactly 32 bits and is taken as a signed integer.

--
==================
Remove the "x" from my email address
Jerry Stuckle
JDS Computer Training Corp.
js*******@attglobal.net
==================
Jan 16 '06 #6
yawnmoth wrote:
Palle Hansen wrote:
yawnmoth wrote:
Using >> normally shifts bits to the right x number of times, where x
is specified by the programmer. As an example, 0x40000000 >> 8 yields
0x00400000. This makes me wonder... why doesn't the same thing happen
with 0x80000000 >> 8? The number it yields is 0xff800000 - not
0x00800000. The following script better demonstrates this:

<?
echo sprintf('%08x',0x40000000 >> 8)."\n";
echo sprintf('%08x',0x80000000 >> 8);
?>

Anyway, any ideas?


My guess is that PHP sees 0x8000000 as a *signed* integer

Why should >> even be concerned with whether or not integers are signed?


Well, it's got to make a decision one way or the other. As a signed
integer, 0x80000000 is -2,147,483,648. Shift right one bit and you get
0xc0000000, which is 1,073,741,824 - the correct result for dividing by 2.

--
==================
Remove the "x" from my email address
Jerry Stuckle
JDS Computer Training Corp.
js*******@attglobal.net
==================
Jan 16 '06 #7
Chung Leong wrote:
Palle Hansen wrote:
yawnmoth wrote:
> <?
> echo sprintf('%08x',0x40000000 >> 8)."\n";
> echo sprintf('%08x',0x80000000 >> 8);
> ?>
My guess is that PHP sees 0x8000000 as a *signed* integer
No, PHP sees 0x80000000 as a double, because the number is beyond the
range of an integer (on 32 bit systems).


Right, but the >> operator "casts" the float to an int.

~$ php -r '$x = 0x80000000; var_dump($x);'
float(2147483648)

~$ php -r '$x = 0x80000000 >> 0; var_dump($x);'
int(-2147483648)

--
If you're posting through Google read <http://cfaj.freeshell.org/google>
Jan 16 '06 #8
yawnmoth wrote:
Why should >> even be concerned with whether or not integers are signed?


~$ php -r 'echo -2 << 2, "\n";'
-8
~$ php -r 'echo -8 >> 2, "\n";'
-2

--
If you're posting through Google read <http://cfaj.freeshell.org/google>
Jan 16 '06 #9
Pedro Graca wrote:
yawnmoth wrote:
Why should >> even be concerned with whether or not integers are signed?


~$ php -r 'echo -8 >> 2, "\n";'


I forgot the rest of the post ...

Let's say -8 in binary is (ignore the spaces)
MSB == 10000000 00000000 00000000 00001000 == LSB

if you shift this right without concern for the sign, you get
MSB == 00100000 00000000 00000000 00000010 == LSB

which is 536870914
Do you think -8 >> 2 (-8 divided by 4) should equal 536870914? :)

--
If you're posting through Google read <http://cfaj.freeshell.org/google>
Jan 16 '06 #10
Pedro Graca wrote:
Pedro Graca wrote:
yawnmoth wrote:
Why should >> even be concerned with whether or not integers are signed?


~$ php -r 'echo -8 >> 2, "\n";'

I forgot the rest of the post ...

Let's say -8 in binary is (ignore the spaces)
MSB == 10000000 00000000 00000000 00001000 == LSB

if you shift this right without concern for the sign, you get
MSB == 00100000 00000000 00000000 00000010 == LSB

which is 536870914
Do you think -8 >> 2 (-8 divided by 4) should equal 536870914? :)


But -8 binary is:

11111111 11111111 11111111 11111000

--
==================
Remove the "x" from my email address
Jerry Stuckle
JDS Computer Training Corp.
js*******@attglobal.net
==================
Jan 16 '06 #11
Jerry Stuckle wrote:
Pedro Graca wrote:

Let's say -8 in binary is (ignore the spaces)
MSB == 10000000 00000000 00000000 00001000 == LSB

if you shift this right without concern for the sign, you get
MSB == 00100000 00000000 00000000 00000010 == LSB

which is 536870914
Do you think -8 >> 2 (-8 divided by 4) should equal 536870914? :)


But -8 binary is:

11111111 11111111 11111111 11111000


Indeed it is (on my machines).
However some other machine running PHP could use sign-and-magnitude
representation of negative numbers instead of two's complement.
For that machine my reasoning above stands :-)

My book on C (The C Programming Language, Kernighan & Ritchie) says this
about >>

<quote>
Right shifting a signed quantity will fill with sign bits
("arithmetic shift") on some machines and with 0-bits
("logical shift") on others.
</quote>

So, taking into account that PHP is written in C, I guess the effect of
0x80000000 >> 8
is implementation defined (can be 0xff800000 on some (most) machines
and 0x00800000 on other machines)

And as PHP does not have C's `unsigned long int` it's best to avoid
right shifting negative values.

--
If you're posting through Google read <http://cfaj.freeshell.org/google>
Jan 17 '06 #12
Pedro Graca wrote:
Jerry Stuckle wrote:
Pedro Graca wrote:
Let's say -8 in binary is (ignore the spaces)
MSB == 10000000 00000000 00000000 00001000 == LSB

if you shift this right without concern for the sign, you get
MSB == 00100000 00000000 00000000 00000010 == LSB

which is 536870914
Do you think -8 >> 2 (-8 divided by 4) should equal 536870914? :)


But -8 binary is:

11111111 11111111 11111111 11111000

Indeed it is (on my machines).
However some other machine running PHP could use sign-and-magnitude
representation of negative numbers instead of two's complement.
For that machine my reasoning above stands :-)

My book on C (The C Programming Language, Kernighan & Ritchie) says this
about >>

<quote>
Right shifting a signed quantity will fill with sign bits
("arithmetic shift") on some machines and with 0-bits
("logical shift") on others.
</quote>

So, taking into account that PHP is written in C, I guess the effect of
0x80000000 >> 8
is implementation defined (can be 0xff800000 on some (most) machines
and 0x00800000 on other machines)

And as PHP does not have C's `unsigned long int` it's best to avoid
right shifting negative values.


Pedro,

Just because it's undefined in C doesn't mean it has to be in PHP.
Different languages can have different rules.

And everything is eventually built on machine language anyway.

--
==================
Remove the "x" from my email address
Jerry Stuckle
JDS Computer Training Corp.
js*******@attglobal.net
==================
Jan 17 '06 #13

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

2 posts views Thread by franklini | last post: by
3 posts views Thread by Iwanow | last post: by
4 posts views Thread by jienweiwu | last post: by
28 posts views Thread by Kent Feiler | last post: by
6 posts views Thread by =?iso-8859-2?Q?K=F8i=B9tof_=AEelechovski?= | last post: by
10 posts views Thread by jason.cipriani | last post: by
reply views Thread by mihailmihai484 | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.