"Hans van Kranenburg" <f0****@xs4all.nl> wrote in message
news:42*********************@news.xs4all.nl...
Bob Purdon wrote: Consider this code:
<?
$mask_n = (pow(2,32) - (pow(2,32-24)-1));
printf("%x\n", $mask_n);
?>
On PHP 4.1.2 it prints:
ffffff00
On PHP 4.3.10 is prints:
ffffff01
Both versions of PHP are the standard Debian packaged versions (4.1.2
from Woody, 4.3.10 from Sarge)
Some other code:
<pre>
<?
$mask_n = (pow(2,32) - (pow(2,32-24)-1));
var_dump($mask_n);
printf("%x\n", $mask_n);
$mask_n2 = 4294967041;
var_dump($mask_n2);
printf("%x\n", $mask_n2);
echo "so... what's the difference ... " . ($mask_n - $mask_n2);
?>
</pre>
On woody 4.1.2:
float(4294967041)
ffffff00
float(4294967041)
ffffff01
so... what's the difference ... -3.3378601074219E-06
On sarge 4.3.10:
float(4294967041)
ffffff01
float(4294967041)
ffffff01
so... what's the difference ... 0
What's going on?!
Hans van Kranenburg
I imagine the relevant statement from the manual is:
"If possible, this function will return an integer"
Your expression would be OK if indeed it were calculated in integers. But
since 2 raised to the power 32 cannot be represented in 32 bits (it misses
by 1), you're thrown into the realm of floating point, and in that world,
you can't assume all bits will be as you think they will be, only that the
numeric values will be sufficiently close to the exact result. And in
floating point, the *order* in which you do arithmetic matters, quite a lot.
As to your code, the most straight-forward way to create bit masks (which is
what I'm thinking you are trying to do) is like this:
$mask = 0xFFFFFFFF << (32 - 8)
which will reliably give you:
0xFFFFFF00
Further, if this were my software, I'd simply write:
$mask = 0xFFFFFF00;
because that says, as clearly as can be said, "I want a 32-bit mask with the
high 24 bits set and the low 8 bits clear".
If I had a variable that specified the number of low zero bits I needed, I'd
write:
$mask = 0xFFFFFFFF << (32 - $low_zero_bits);
because that says, as clearly as can be said, "I want a mask that's 32 bits
wide and is everywhere 1's except for the $low_zero_bits which are zero".
Finally, if you want this to work cross-platform, you should define a
constant that's the number of bits in an integer, and work from that,
remembering to never shift by more than that many bits, since Intel
disagrees with most of the rest of the world as to the meaning of
over-shifting (shifting more than 32 on a 32-bit machine, for example).