Truques Bitwise em PHP - One-Liners
Coleção de truques rápidos e hacks usando operações bitwise em PHP
⚡ Truques Bitwise em PHP
Coleção de one-liners e hacks práticos usando operações bitwise.
🔢 Verificações Rápidas
Verificar se número é par
<?php
$isPar = ($n & 1) === 0;
// Exemplos:
var_dump(4 & 1 === 0); // true (par)
var_dump(7 & 1 === 0); // false (ímpar)
Verificar se número é ímpar
<?php
$isImpar = ($n & 1) === 1;
// Ou simplesmente:
$isImpar = $n & 1; // Retorna 1 (truthy) se ímpar, 0 (falsy) se par
Verificar se número é potência de 2
<?php
$isPowerOf2 = ($n > 0) && (($n & ($n - 1)) === 0);
// Exemplos:
// 8: 1000 & 0111 = 0000 ✓
// 16: 10000 & 01111 = 00000 ✓
// 6: 0110 & 0101 = 0100 ✗
Verificar se dois números têm sinais opostos
<?php
$oppositeSign = ($a ^ $b) < 0;
// Se XOR for negativo, têm sinais diferentes
var_dump((5 ^ -3) < 0); // true
var_dump((5 ^ 3) < 0); // false
🎯 Manipulação de Bits
Obter bit em posição específica
<?php
function getBit($num, $pos) {
return ($num >> $pos) & 1;
}
// Exemplo: obter 3º bit de 13 (1101)
echo getBit(13, 2); // 1
// Saída esperada
// 1
Setar bit em posição específica (torná-lo 1)
<?php
function setBit($num, $pos) {
return $num | (1 << $pos);
}
// Exemplo: setar 2º bit de 8 (1000) → 12 (1100)
echo setBit(8, 2); // 12
// Saída esperada
// 12
Limpar bit em posição específica (torná-lo 0)
<?php
function clearBit($num, $pos) {
return $num & ~(1 << $pos);
}
// Exemplo: limpar 3º bit de 15 (1111) → 7 (0111)
echo clearBit(15, 3); // 7
// Saída esperada
// 7
Alternar bit em posição específica (flip)
<?php
function toggleBit($num, $pos) {
return $num ^ (1 << $pos);
}
// Exemplo: toggle 2º bit de 12 (1100) → 8 (1000)
echo toggleBit(12, 2); // 8
// Saída esperada
// 8
Contar quantos bits estão setados (população de bits)
<?php
function popCount($n) {
$count = 0;
while ($n) {
$count += $n & 1;
$n >>= 1;
}
return $count;
}
// Método Brian Kernighan (mais eficiente)
function popCountFast($n) {
$count = 0;
while ($n) {
$n &= $n - 1; // Remove o bit 1 mais à direita
$count++;
}
return $count;
}
echo popCount(13); // 3 (1101 tem três bits 1)
echo popCountFast(15); // 4 (1111 tem quatro bits 1)
// Saída esperada
// 34
🚀 Otimizações Matemáticas
Multiplicar por potência de 2
<?php
$multiply2 = $n << 1; // $n * 2
$multiply4 = $n << 2; // $n * 4
$multiply8 = $n << 3; // $n * 8
$multiply16 = $n << 4; // $n * 16
// Exemplo:
echo 5 << 3; // 40 (5 * 8)
Dividir por potência de 2 (divisão inteira)
<?php
$divide2 = $n >> 1; // floor($n / 2)
$divide4 = $n >> 2; // floor($n / 4)
$divide8 = $n >> 3; // floor($n / 8)
// Exemplo:
echo 20 >> 2; // 5 (20 / 4)
Obter módulo de potência de 2
<?php
// $n % $powerOf2 pode ser otimizado
$mod2 = $n & 1; // $n % 2
$mod4 = $n & 3; // $n % 4
$mod8 = $n & 7; // $n % 8
$mod16 = $n & 15; // $n % 16
// Exemplo:
echo 13 & 7; // 5 (13 % 8)
Trocar sinal (negativo ↔ positivo)
<?php
$opposite = ~$n + 1;
// Exemplos:
echo ~5 + 1; // -5
echo ~(-5) + 1; // 5
Valor absoluto sem condicionais
<?php
function abs($n) {
$mask = $n >> 31; // -1 se negativo, 0 se positivo
return ($n + $mask) ^ $mask;
}
// Ou mais simples (funciona apenas em 32-bit):
function absFast($n) {
$mask = $n >> (PHP_INT_SIZE * 8 - 1);
return ($n ^ $mask) - $mask;
}
Máximo de dois números sem condicionais
<?php
function max($a, $b) {
return $a ^ (($a ^ $b) & -($a < $b));
}
Mínimo de dois números sem condicionais
<?php
function min($a, $b) {
return $b ^ (($a ^ $b) & -($a < $b));
}
🔄 Truques de Troca
Trocar dois valores sem variável temporária
<?php
// Método 1: XOR
$a = $a ^ $b;
$b = $a ^ $b;
$a = $a ^ $b;
// Método 2: Soma/Subtração (cuidado com overflow)
$a = $a + $b;
$b = $a - $b;
$a = $a - $b;
Trocar nibbles (4 bits) de um byte
<?php
function swapNibbles($n) {
return (($n & 0x0F) << 4) | (($n & 0xF0) >> 4);
}
// Exemplo: 0x3A (0011 1010) → 0xA3 (1010 0011)
printf("0x%X\n", swapNibbles(0x3A)); // 0xA3
// Saída esperada
// 0xA3
🎨 Máscaras e Flags
Verificar múltiplas flags de uma vez
<?php
define('FLAG_A', 1);
define('FLAG_B', 2);
define('FLAG_C', 4);
$flags = FLAG_A | FLAG_C; // 0101
// Verificar se TEM Flag A
$hasA = ($flags & FLAG_A) !== 0; // true
// Verificar se TEM Flag A E Flag C
$hasAC = ($flags & (FLAG_A | FLAG_C)) === (FLAG_A | FLAG_C); // true
// Verificar se TEM pelo menos uma das flags
$hasAnyAC = ($flags & (FLAG_A | FLAG_C)) !== 0; // true
Setar múltiplas flags
<?php
$flags |= FLAG_A | FLAG_B; // Adiciona FLAG_A e FLAG_B
Remover múltiplas flags
<?php
$flags &= ~(FLAG_A | FLAG_B); // Remove FLAG_A e FLAG_B
Toggle múltiplas flags
<?php
$flags ^= FLAG_A | FLAG_B; // Alterna FLAG_A e FLAG_B
🎯 Casos de Uso Práticos
RGB para Hexadecimal e vice-versa
<?php
// RGB para HEX
function rgbToHex($r, $g, $b) {
return ($r << 16) | ($g << 8) | $b;
}
// HEX para RGB
function hexToRgb($hex) {
return [
'r' => ($hex >> 16) & 0xFF,
'g' => ($hex >> 8) & 0xFF,
'b' => $hex & 0xFF
];
}
// Exemplo:
$hex = rgbToHex(255, 128, 64); // 0xFF8040
$rgb = hexToRgb(0xFF8040); // ['r'=>255, 'g'=>128, 'b'=>64]
Arredondar para próxima potência de 2
<?php
function nextPowerOf2($n) {
$n--;
$n |= $n >> 1;
$n |= $n >> 2;
$n |= $n >> 4;
$n |= $n >> 8;
$n |= $n >> 16;
return $n + 1;
}
echo nextPowerOf2(10); // 16
echo nextPowerOf2(33); // 64
// Saída esperada
// 1664
Inverter bits de um número
<?php
function reverseBits($n, $bits = 8) {
$result = 0;
for ($i = 0; $i < $bits; $i++) {
$result = ($result << 1) | ($n & 1);
$n >>= 1;
}
return $result;
}
// Exemplo: 10 (00001010) → 80 (01010000) em 8 bits
echo reverseBits(10, 8); // 80
// Saída esperada
// 80
Encontrar bit diferente entre dois números
<?php
function findDifferentBit($a, $b) {
$xor = $a ^ $b;
return log($xor & -$xor, 2); // Posição do bit diferente
}
// Exemplo: 5 (0101) vs 7 (0111)
echo findDifferentBit(5, 7); // 1 (segundo bit é diferente)
// Saída esperada
// 1
🧮 Truques Avançados
Encontrar número que aparece uma vez (todos os outros aparecem duas vezes)
<?php
function findSingle($arr) {
$result = 0;
foreach ($arr as $num) {
$result ^= $num; // XOR cancela pares
}
return $result;
}
echo findSingle([2, 3, 5, 4, 5, 3, 4]); // 2
// Saída esperada
// 2
Detectar se inteiro tem sinais alternados em binário
<?php
function hasAlternatingBits($n) {
$xor = $n ^ ($n >> 1);
return ($xor & ($xor + 1)) === 0;
}
// Exemplos:
var_dump(hasAlternatingBits(5)); // true (101)
var_dump(hasAlternatingBits(10)); // true (1010)
var_dump(hasAlternatingBits(7)); // false (111)
// Saída esperada
// bool(true)
// bool(true)
// bool(false)
Transformar maiúscula em minúscula e vice-versa
<?php
// ASCII: 'A' = 65 (01000001), 'a' = 97 (01100001)
// Diferença está no 6º bit (32 = 0x20)
$lowercase = chr(ord('A') | 0x20); // 'a'
$uppercase = chr(ord('a') & ~0x20); // 'A'
// Toggle case:
$toggled = chr(ord('A') ^ 0x20); // 'a'
💡 Dicas de Performance
<?php
// ✅ RÁPIDO: Usar shift para multiplicar/dividir por potências de 2
$fast = $n << 3; // $n * 8
// ❌ LENTO: Multiplicação convencional
$slow = $n * 8;
// ✅ RÁPIDO: Usar AND para módulo de potência de 2
$fast = $n & 7; // $n % 8
// ❌ LENTO: Módulo convencional
$slow = $n % 8;
// ✅ RÁPIDO: Verificar par/ímpar
$fast = $n & 1;
// ❌ LENTO: Módulo
$slow = $n % 2;
⚠️ Armadilhas Comuns
<?php
// ❌ CUIDADO: Precedência de operadores
$wrong = $n & 1 === 0; // Avalia (1 === 0) primeiro!
$correct = ($n & 1) === 0; // ✅ Correto
// ❌ CUIDADO: Overflow em deslocamentos
$overflow = 1 << 64; // Comportamento indefinido!
// ❌ CUIDADO: NOT (~) em números negativos
$weird = ~-1; // Resultado pode surpreender!
🎓 Cheat Sheet
<?php
// Verificações
$n & 1 // Par? (0 = par, 1 = ímpar)
($n & ($n-1)) === 0 // É potência de 2?
// Operações rápidas
$n << k // Multiplica por 2^k
$n >> k // Divide por 2^k
$n & (2^k - 1) // Módulo por 2^k
// Manipulação
$n | (1 << k) // Seta bit k
$n & ~(1 << k) // Limpa bit k
$n ^ (1 << k) // Toggle bit k
($n >> k) & 1 // Lê bit k
// Truques
$a ^ $b // Troca sem temp
~$n + 1 // Troca sinal
$n & -$n // Isola bit mais à direita
🔗 Recursos Relacionados
- Ver também: Operações Bitwise em PHP para explicações detalhadas
- Tags relacionadas: performance, otimização, flags, permissões
Lembre-se: bitwise é poderoso, mas priorize legibilidade sobre micro-otimizações prematuras! ⚡