コード例 #1
0
/**
 * 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
/**
 * Compute the parity of a number by breaking it into smaller words and xor'ing the parity of each word.  The first
 * step is to cache the parity of all words and then we can use the cached values to speed up the check of the
 * number we want to test.
 * i.e.
 * 64 = 1000000 which is
 * parity[00000000] ^ parity[00000000] ^ parity[00000000] ^ parity[00000000] ^ parity[00000000] ^ parity[00000000] ^ parity[01000000] or
 * 0 ^ 0 ^ 0 ^ 0 ^ 0 ^ 0 ^ 0 ^ 1 = 1
 *
 * @param $number
 * @return int
 * @throws \InvalidArgumentException
 */
function computeParityCache($number)
{
    if (!is_int($number)) {
        throw new \InvalidArgumentException('$number must be an integer');
    }
    $bitwiseHelper = new BitwiseHelper();
    $number = $bitwiseHelper->eraseSignBit($number);
    $precomputedParities = getParityOfWords();
    $bitmask = 0b11111111;
    // 32-bit implementation
    if (PHP_INT_SIZE == 4) {
        return $precomputedParities[$number >> 3 * BitwiseHelper::WORD_SIZE & $bitmask] ^ $precomputedParities[$number >> 2 * BitwiseHelper::WORD_SIZE & $bitmask] ^ $precomputedParities[$number >> BitwiseHelper::WORD_SIZE & $bitmask] ^ $precomputedParities[$number & $bitmask];
    }
    // 64-bit implementation
    return $precomputedParities[$number >> 7 * BitwiseHelper::WORD_SIZE & $bitmask] ^ $precomputedParities[$number >> 6 * BitwiseHelper::WORD_SIZE & $bitmask] ^ $precomputedParities[$number >> 5 * BitwiseHelper::WORD_SIZE & $bitmask] ^ $precomputedParities[$number >> 4 * BitwiseHelper::WORD_SIZE & $bitmask] ^ $precomputedParities[$number >> 3 * BitwiseHelper::WORD_SIZE & $bitmask] ^ $precomputedParities[$number >> 2 * BitwiseHelper::WORD_SIZE & $bitmask] ^ $precomputedParities[$number >> BitwiseHelper::WORD_SIZE & $bitmask] ^ $precomputedParities[$number & $bitmask];
}
コード例 #3
0
ファイル: reverse_bits.php プロジェクト: perfectgait/eopi
/**
 * Reverse the bits in a number.  This works by first caching the values of all 8-bit words with their bits reversed.
 * Then, using the cached values each 8-bit segment of the number is used to build the number with all bits reversed.
 * The least significant 8-bits of the number are reversed and used as the most significant 8-bits.  Then the next
 * least significant and so on.
 *
 * @param int $number
 * @return int
 * @throws \InvalidArgumentException
 */
function reverseBits($number)
{
    if (!is_int($number)) {
        throw new \InvalidArgumentException('$number must be an integer');
    }
    $bitwiseHelper = new BitwiseHelper();
    $number = $bitwiseHelper->eraseSignBit($number);
    $precomputedReverses = getReverseOf8BitWords();
    $bitmask = 0b11111111;
    // 32-bit implementation
    if (PHP_INT_SIZE == 4) {
        return $precomputedReverses[$number & $bitmask] << 3 * BitwiseHelper::WORD_SIZE | $precomputedReverses[$number >> BitwiseHelper::WORD_SIZE & $bitmask] << 2 * BitwiseHelper::WORD_SIZE | $precomputedReverses[$number >> 2 * BitwiseHelper::WORD_SIZE & $bitmask] << BitwiseHelper::WORD_SIZE | $precomputedReverses[$number >> 3 * BitwiseHelper::WORD_SIZE & $bitmask];
    }
    // 64-bit implementation
    return $precomputedReverses[$number & $bitmask] << 7 * BitwiseHelper::WORD_SIZE | $precomputedReverses[$number >> BitwiseHelper::WORD_SIZE & $bitmask] << 6 * BitwiseHelper::WORD_SIZE | $precomputedReverses[$number >> 2 * BitwiseHelper::WORD_SIZE & $bitmask] << 5 * BitwiseHelper::WORD_SIZE | $precomputedReverses[$number >> 3 * BitwiseHelper::WORD_SIZE & $bitmask] << 4 * BitwiseHelper::WORD_SIZE | $precomputedReverses[$number >> 4 * BitwiseHelper::WORD_SIZE & $bitmask] << 3 * BitwiseHelper::WORD_SIZE | $precomputedReverses[$number >> 5 * BitwiseHelper::WORD_SIZE & $bitmask] << 2 * BitwiseHelper::WORD_SIZE | $precomputedReverses[$number >> 6 * BitwiseHelper::WORD_SIZE & $bitmask] << BitwiseHelper::WORD_SIZE | $precomputedReverses[$number >> 7 * BitwiseHelper::WORD_SIZE & $bitmask];
}
コード例 #4
0
/**
 * 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;
}