/**
 * Compute the parity of a number using a technique to erase the LSB.
 *
 * i.e.
 * 64 = 1000000
 * 1000000 / result = 1
 * parity of 64 is 1
 * This works because 64 is &'d with 63 = 1000000 is &'d with 0111111.  As we can see that operation will return 0
 * which evaluates to false so the while loop terminates.
 *
 * 65 = 1000001
 * 1000001 / result = 1
 * 1000000 / result = 0
 * parity of 65 is 0
 *
 * This improves performance in the best and average cases but can still be as slow as brute force.  For example if run
 * on 9223372036854775807 it will take 63 iterations which matches brute force.
 *
 * @param int $number
 * @return int
 * @throws \InvalidArgumentException
 */
function computeParityEraseLowestSetBit($number)
{
    if (!is_int($number)) {
        throw new \InvalidArgumentException('$number must be an integer');
    }
    $bitwiseHelper = new BitwiseHelper();
    $number = $bitwiseHelper->eraseSignBit($number);
    $result = 0;
    while ($number) {
        $result ^= 1;
        $number &= $number - 1;
    }
    return $result;
}
示例#2
0
/**
 * Get an array of the pre-computed reverse of all 8-bit words
 *
 * @return array
 */
function getReverseOf8BitWords()
{
    static $cachedReverses = [];
    if (empty($cachedReverses)) {
        if (!file_exists('computed_reverses.txt')) {
            $bitwiseHelper = new BitwiseHelper();
            $cachedReverses = $bitwiseHelper->computeReverseOf8BitWords(0b11111111);
            $fp = fopen('computed_reverses.txt', 'w');
            fwrite($fp, serialize($cachedReverses));
            fclose($fp);
        } else {
            $cachedReverses = unserialize(file_get_contents('computed_reverses.txt'));
        }
    }
    return $cachedReverses;
}
/**
 * Compute the parity of a number by comparing the number to smaller halves of itself over and over.  Because XOR is
 * commutative we can do this until we are down to 4 bits and then use a pre-computed lookup table to compute the final
 * parity.
 * i.e.
 * 64 = 0000000000000000000000000000000000000000000000000000000001000000
 *
 * 0000000000000000000000000000000000000000000000000000000001000000
 * ^                               00000000000000000000000000000000 / Shift 32 bits
 * --------------------------------------------------------------------
 * 0000000000000000000000000000000000000000000000000000000001000000
 * ^               000000000000000000000000000000000000000000000000 / Shift 16 bits
 * --------------------------------------------------------------------
 * 0000000000000000000000000000000000000000000000000000000001000000
 * ^       00000000000000000000000000000000000000000000000000000000 / Shift 8 bits
 * --------------------------------------------------------------------
 * 0000000000000000000000000000000000000000000000000000000001000000
 * ^   000000000000000000000000000000000000000000000000000000000100 / Shift 4 bits
 * --------------------------------------------------------------------
 * 0000000000000000000000000000000000000000000000000000000001000100
 *                                                             0100 / Last 4 bits
 *                 0110100110010110 >> 4 & 1 = 011010011001 & 1 = 1 / Parity
 *
 * 65 = 0000000000000000000000000000000000000000000000000000000001000001
 *
 * 0000000000000000000000000000000000000000000000000000000001000001
 * ^                               00000000000000000000000000000000 / Shift 32 bits
 * --------------------------------------------------------------------
 * 0000000000000000000000000000000000000000000000000000000001000001
 * ^               000000000000000000000000000000000000000000000000 / Shift 16 bits
 * --------------------------------------------------------------------
 * 0000000000000000000000000000000000000000000000000000000001000001
 * ^       00000000000000000000000000000000000000000000000000000000 / Shift 8 bits
 * --------------------------------------------------------------------
 * 0000000000000000000000000000000000000000000000000000000001000001
 * ^   000000000000000000000000000000000000000000000000000000000100 / Shift 4 bits
 * --------------------------------------------------------------------
 * 0000000000000000000000000000000000000000000000000000000001000101
 *                                                             0101 / Last 4 bits
 *                  0110100110010110 >> 5 & 1 = 01101001100 & 1 = 0 / Parity
 *
 * @param $number
 * @return int
 * @throws \InvalidArgumentException
 */
function computeParityShifting($number)
{
    if (!is_int($number)) {
        throw new \InvalidArgumentException('$number must be an integer');
    }
    $bitwiseHelper = new BitwiseHelper();
    $number = $bitwiseHelper->eraseSignBit($number);
    // This contains the parity of 0, 1, 2 ... starting from the LSB
    static $fourBitLookupTable = 0b110100110010110;
    if (PHP_INT_SIZE == 8) {
        $number ^= $number >> BitwiseHelper::WORD_SIZE * 4;
    }
    $number ^= $number >> BitwiseHelper::WORD_SIZE * 2;
    $number ^= $number >> BitwiseHelper::WORD_SIZE;
    $number ^= $number >> BitwiseHelper::WORD_SIZE / 2;
    $number &= 0b1111;
    return $fourBitLookupTable >> $number & 1;
}