Performing a bitwise NOT on arbitrarily long integers

Here’s the surprisingly simple solution to a fairly challenging problem. I do not understand why PHPs GMP extension does not include a gmp_not() function.

function gmp_not($n) {
	
	# convert to binary string
	$n = gmp_strval($n, 2);
	
	# invert each bit, one at a time
	for($i = 0; $i < strlen($n); $i++) {
		$n[$i] = ~$n[$i];
	}
	
	# convert back to decimal
	return gmp_strval(gmp_init($n, 2), 10);
}

2 thoughts on “Performing a bitwise NOT on arbitrarily long integers”

  1. The gmp_com function calculates one’s compliment (a bitwise NOT). Just remember to mask its result or you’ll end up with a signed integer!

    For example:

    10011010010 is 1234
    11111111111 is 2047, my chosen mask

    echo gmp_strval(gmp_and(gmp_com('1234'), '2047'), 2);
    >> 1100101101

    The first line is the original (1234). The second line is its masked bitwise NOT:

    10011010010
    01100101101

    I find it easier to think of binary in the context of its register. So 2047 is the maximum value an 11-bit register can handle.

  2. Or just perform an XOR with the same mask value:

    echo gmp_strval(gmp_xor(‘1234’, ‘2047’), 2);
    >> 1100101101

    But both of those methods get cumbersome when you’re trying to invert, say, a (128-bit) IPv6 address, and you have to use a mask like “0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF”. That’s still easier than writing a whole separate function to handle it, but GMP should really incorporate this basic feature.

Leave a Reply

Your email address will not be published. Required fields are marked *