adept-digital / int-utils
Utilities for emulating WebAssembly 32-bit and 64-bit integer operations in PHP.
Requires
- php-64bit: >=8.4
Requires (Dev)
- phpunit/phpunit: ^12
README
Utilities for emulating WebAssembly 32-bit and 64-bit integer operations in PHP. These may be useful for porting an application or library from C, C++, or other languages.
Requirements
This package requires a 64-bit build of PHP 8.4 or later.
There is no dependency on external Composer packages or PHP extensions.
Installation
Install via Composer.
composer require adept-digital/int-utils
Usage
There are two classes with near-identical interfaces:
\AdeptDigital\IntUtils\Int32
\AdeptDigital\IntUtils\Int64
The following operations are provided:
add(int $a, int $b): int
: Integer addition.sub(int $a, int $b): int
: Integer subtraction.mul(int $a, int $b): int
: Integer multiplication.div_s(int $a, int $b): int
: Signed integer division. 1div_u(int $a, int $b): int
: Unsigned integer division.rem_s(int $a, int $b): int
: Signed integer modulo. 1rem_u(int $a, int $b): int
: Unsigned integer modulo.eq(int $a, int $b): int
: Equal comparison. 2eqz(int $a): int
: Equals zero test. 2ne(int $a, int $b): int
: Not equal comparison. 2lt_s(int $a, int $b): int
: Signed less than comparison. 2lt_u(int $a, int $b): int
: Unsigned less than comparison.le_s(int $a, int $b): int
: Signed less than or equal comparison. 2le_u(int $a, int $b): int
: Unsigned less than or equal comparison.gt_s(int $a, int $b): int
: Signed greater than comparison. 2gt_u(int $a, int $b): int
: Unsigned greater than comparison.ge_s(int $a, int $b): int
: Signed greater than or equal comparison. 2ge_u(int $a, int $b): int
: Unsigned greater than or equal comparison.and(int $a, int $b): int
: Bitwise AND. 1or(int $a, int $b): int
: Bitwise OR. 1xor(int $a, int $b): int
: Bitwise XOR. 1shl(int $a, int $b): int
: Shift left. 2shr_s(int $a, int $b): int
: Signed (arithmetic) shift right. 2shr_u(int $a, int $b): int
: Unsigned (logical) shift right.rotl(int $a, int $b): int
: Rotate left.rotr(int $a, int $b): int
: Rotate right.clz(int $a): int
: Count leading zeros.ctz(int $a): int
: Count trailing zeros.popcnt(int $a): int
: Population count.extend8_s(int $a): int
: Extend the sign of the least significant 8 bits.extend16_s(int $a): int
: Extend the sign of the least significant 16 bits.extend32_s(int $a): int
: Extend the sign of the least significant 32 bits. 3
32-bit representation
PHP has no 32-bit integer type, so 32-bit numbers are represented in 64-bit, but are limited to the range of a signed
32-bit integer (-2,147,483,648
to 2,147,483,647
). For example, 4,294,967,295
(2**32-1
) should be represented as
-1
. Using numbers outside this range will cause a RangeException
to be thrown, unless assertions are disabled, in
which case the result is undefined.
To correctly format an unsigned 32-bit integer, unset the most significant 32 bits:
use \AdeptDigital\IntUtils\Int32; echo Int32::add(Int32::MAX, 1) & 0xFFFF_FFFF; // output: 2147483648
64-bit representation
PHP has no unsigned integer type, so numbers larger than PHP_INT_MAX
will appear to be negative.
To correctly format an unsigned integer, use printf()
or sprintf()
:
use \AdeptDigital\IntUtils\Int64; printf('%u', Int64::add(Int64::MAX, 1)); // output: 9223372036854775808
Contributing
All contributions are welcome. If you would like to work on a new feature, consider creating an issue before starting.
TODO
- Add benchmarks and benchmark on different machines.
- Add alternative implementations (eg: GMP, FFI, custom extension).
- Add feature detection for alternative implementations.
License
Copyright 2025 David Gallagher david@adeptdigital.com.au.
The package is licensed under the GNU Lesser General Public License 3.0 or later.