Re: signed int64 pack/unpack [message #184593 is a reply to message #184590] |
Sun, 12 January 2014 15:25 |
cameron7
Messages: 8 Registered: January 2014
Karma:
|
Junior Member |
|
|
I guess I'll reply with my own solution. Turns out there are 2 separate issues here.
1) the "signed" bit needs to be flipped back to 0 before converting to int. This is because it appears the conversion from base 2 to base 10 will always assume the end value is positive.
2) Because of this, the rest of the bits need to be flipped.
So I added 2 arguments to the function, one will tell us if we're supposed to be checking for a "signed bit", and the other will tell us if we need to flip bits.
As you'll see I'm still off by 1 in the end result, but I'm sure that's just in the details.
I hope you'll all agree, this is really ugly, but seems to work :)
<?php
$i64 = -8223372036854775807;
echo "PACKING: ".$i64.PHP_EOL;
list(,$binary) = getBinaryString($i64, 64);
list(,$i64a) = unpack('N', pack('N', base_convert(substr($binary, 0, 32), 2, 10)));
list(,$i64b) = unpack('N', pack('N', base_convert(substr($binary, 32, 32), 2, 10)));
list($flag,$i64c)= getBinaryString($i64a, 32, true, true);
list(,$i64d) = getBinaryString($i64b, 32, false, true);
$unpack = base_convert($i64c.$i64d,2,10);
$unpack *= $flag ? -1 : 1;
echo "UNPACKED: ".$unpack.PHP_EOL;
function getBinaryString($packed,$bits,$check_signed = false, $flip = false){
$a = 0x01;
$binary = '';
for($x=0; $x<$bits; $x++){
$binary .= (int)(bool)($a & $packed);
$a = $a << 1;
}
$signed_flag = false;
if($check_signed && substr($binary,$bits-1,1) === '1'){
$signed_flag = true;
}
if($flip){
for($x=0;$x<strlen($binary);$x++){
$binary[$x] = $binary[$x] === '1' ? '0' : '1';
}
}
if($signed_flag){
$binary = substr($binary,0,$bits-1).'0';
}
return array($signed_flag, strrev($binary));
}
|
|
|