Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Splitting UInt64 into 2 UInt32 values

Tags:

php

I have a UInt64 stored in a string. For the sake of argument, let's use the max value, 18446744073709551615. Since PHP does not support UInt64, I cannot ever convert this into a number, else bits will be lost.

So it my initial approach was packing:

$number = "18446744073709551615";
$packed = pack('J', $number);
$value1 = unpack('N', substr($packed, 0, 4))[1];
$value2 = unpack('N', substr($packed, 4, 4))[1];
var_dump($packed); // 7fffffffffffffff

So that's not quite right. Internally, it was still converted into an Int64.

I can pack with N to get the half the value, but I cannot figure out how to get the other half:

$number = "18446744073709551615";
$packed = pack('N', $number);
$value1 = ??;
$value2 = unpack('N', $packed)[1];

Asking for repeats with N* or NN doesn't help. My brain wants to shift the value to the right, but again, I can't convert to an integer, so no bitwise operations.

I feel like I'm missing something really simple. How do I get the other UInt32?

like image 313
Thom McGrath Avatar asked Oct 16 '25 16:10

Thom McGrath


1 Answers

You're not missing anything obvious from my point of view. The issue is that PHP can't handle UInt64 values natively. So rather than trying to use pack('J', $number) (which still requires PHP to convert the string to a 64-bit int internally), I’d approach it like this: use BCMath to split the number into two UInt32 parts and pack those separately. This avoids any precision loss and works entirely with strings. Here’s how I’d do it:

$number = "18446744073709551615";

// Split into high and low 32-bit parts using BCMath
$high = bcdiv($number, bcpow("2", "32"), 0);
$low = bcmod($number, bcpow("2", "32"));

// Pack as two unsigned 32-bit integers (big endian)
$packed = pack("N", (int)$high) . pack("N", (int)$low);
echo bin2hex($packed); // ffffffffffffffff

To reverse the operation and get back the original string:

$unpacked = unpack("Nhigh/Nlow", $packed);

$reconstructed = bcadd(
    bcmul((string)$unpacked['high'], bcpow("2", "32")),
    (string)$unpacked['low']
);


echo $reconstructed; // 18446744073709551615
like image 141
Camilla Giuliani Avatar answered Oct 18 '25 06:10

Camilla Giuliani



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!