5

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?

4 Answers 4

1

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Hey, thx :) can You check if my implementation is working correct?
1

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

Comments

1

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

Comments

-1

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

Generally, see Arithmetic with Arbitrarily Large Integers in PHP

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.