开发者

Write large 4 byte integer as an unsigned, binary

I have integers which floats between values: 4000000000-4294967000 (which is less than int max for a 4 byte unsigned int)

and i want to save it to file, and then re-read value

$f = fopen($fileName, 'wb'); fwrite($f, pack('I', $value));

It is important that in file, value must be exact 4 byte unsigned int, because external devices will expect that format of data. But PHP stores that big values as float, and destroys binary representation.

How i can write that numbers to file in that format?

[EDIT] @FractalizeR thx this works i have:

protected static function handleUint($direction, $value)
{
    if($direction == 'encode')
    {
        $first2bytes    = intval($value / (256 * 256));
        $second2bytes   = intval($value - $first2bytes);

        return pack('n2',开发者_如何学编程 $first2bytes, $second2bytes);
    }
    else
    {
        $arr = unpack('n2ints', $value);
        $value = $arr['ints1'] * (256 * 256) + intval($arr['ints2']) - 1;
        return $value;
    }
}

But i dont quite understand, why i have to -1 on the returning value, and is this binary will be produced correct?


Well, split that 4 bytes number into 2 2-bytes numbers (integer divide by 256*256 to get the first word and subtract that value from original one to get the second one) and write in two packs.


Don't worry about it being a float. If it's between 2^31 and 2^32-1, you won't have any problems.

PHP floats have a 52-bit mantissa and so can store without precision loss 32-bit numbers.

You tell pack to encode an integer and you pass it a float, it will convert the float into an integer. Floats whose value is an integer between 2^31 and 2^32-1, get converted to negative numbers on 32-bit machines:

$ php -r "var_dump((int) 4000000000);"
int(-294967296)

On a 64-bit machine, you get an integer too:

$ php -r "var_dump((int) 4000000000);"
int(4000000000)

But their byte representation is exactly the same. pack will return the same on both:

$ php -r "var_dump(unpack('H*', pack('I', (float) 4000000000)));"
array(1) {
  [1]=>
  string(8) "00286bee"
}


If you want to split your int up into 4 bytes you can do the following:

int x = 13434;
byte[] buff = new byte[] {
       (byte)((x >> 24) & 0xff),
       (byte)((x >> 16) & 0xff),
       (byte)((x >> 8) & 0xff),
       (byte((x) & 0xff)
}

The method used here is called bitwise operations.

See: http://en.wikipedia.org/wiki/Bitwise_operation

Hope this helped.

EDIT:

I think this is how you would do the same in PHP:

$arr = array(
       ((x >> 24) & 0xff),
       ((x >> 16) & 0xff),
       ((x >> 8) & 0xff),
       (x & 0xff)
);

See: http://php.net/manual/en/language.operators.bitwise.php


Use bcmath() to work on your numbers, and for saving, do as FractalizeR said.

Generally, see Arithmetic with Arbitrarily Large Integers in PHP

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜