Записать большое 4-байтовое целое число в виде двоичного числа без знака - PullRequest
5 голосов
/ 31 августа 2010

У меня есть целые числа, которые плавают между значениями: 4000000000-4294967000 (что меньше, чем int max для 4-байтового целого без знака)

, и я хочу сохранить его в файл, а затем перечитать значение

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

Важно, чтобы в файле значение было точно 4-байтовым беззнаковым целым, потому что внешние устройства ожидают такой формат данных.Но PHP хранит эти большие значения как float и уничтожает двоичное представление.

Как я могу записать эти числа в файл в этом формате?

[EDIT] @FractalizeR thxэто работает у меня:

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;
    }
}

Но я не совсем понимаю, почему мне нужно -1 на возвращаемое значение, и будет ли этот двоичный файл будет получен правильно?

Ответы [ 4 ]

1 голос
/ 31 августа 2010

Не беспокойся, что это поплавок. Если это между 2 ^ 31 и 2 ^ 32-1, у вас не будет никаких проблем.

PHP-плавающие имеют 52-битные мантиссы и поэтому могут хранить без потери точности 32-битные числа.

Вы говорите pack, что кодируете целое число, и передаете ему число с плавающей точкой, оно конвертирует число с целым числом. Число с плавающей запятой, значение которого является целым числом от 2 ^ 31 до 2 ^ 32-1, преобразуется в отрицательные числа на 32-разрядных компьютерах:

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

На 64-битной машине вы также получаете целое число:

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

Но их байтовое представление точно такое же. pack вернет одинаковое для обоих:

$ php -r "var_dump(unpack('H*', pack('I', (float) 4000000000)));"
array(1) {
  [1]=>
  string(8) "00286bee"
}
1 голос
/ 31 августа 2010

Ну, разделите это 4-байтовое число на 2 2-байтовых числа (целочисленное деление на 256 * 256, чтобы получить первое слово, и вычтите это значение из исходного, чтобы получить второе), и запишите в два пакета.

1 голос
/ 31 августа 2010

Если вы хотите разделить ваш int на 4 байта, вы можете сделать следующее:

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

Используемый здесь метод называется побитовыми операциями.

См .: http://en.wikipedia.org/wiki/Bitwise_operation

Надеюсь, это помогло.

РЕДАКТИРОВАТЬ:

Я думаю, что это то, как вы бы сделалито же в PHP:

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

См .: http://php.net/manual/en/language.operators.bitwise.php

0 голосов
/ 31 августа 2010

Используйте bcmath () для работы с вашими номерами, а для сохранения сделайте, как сказал FractalizeR.

Как правило, см. Арифметика с произвольно большими целыми числами в PHP

...