Resposta do Desafio do dia / 2
Vamos por partes:
Um dos objetivos deste desafio era demonstrar que blocos de códigos podem ser utilizados em qualquer parte, e não apenas em estruturas de controle, decisão, etc. O seguinte trecho de código é perfeitamente válido e funcional (apesar de “estranho”)
<?php
{
$foo = ‘foo’;
echo $foo;
}
Como pode se observar no desafio, coloquei o código em diversos blocos, mas apenas para isso: Demonstrar que é possível utilizar em qualquer lugar. Para resolução do desafio, é indispensável conhecimento de operações bit-a-bit. Como não é todo mundo que tem esse conhecimento, um outro objetivo do desafio era despertar a curiosidade de quem não soubesse e quisesse resolver e também falar um pouco sobre isso (na resposta). Segue agora então o mesmo código, comentado, com a resposta do desafio:
<?php
// desafio2.php// para acompanhar, segue alguns numeros binarios:
//
// 000 0
// 001 1
// 010 2
// 011 3
// 100 4
// 101 5
// 110 6
// 111 7
// iniciamos $x com valor 2
$x = 2;
{
// aqui temos também um pequeno truque:
// print é utilizado para exibir uma mensagem,
// e sempre retorna 1. Logo, sera exibida a
// mensagem ’Iniciando ’ e $x sera incrementado
// em 1. Neste momento temos:
// $x = 3
$x += print(‘Iniciando ’);
{
// aqui sera exibido ’desafio 2′
echo ‘desafio 2′;
// aqui temos a primeira operacão bit-a-bit,
// um ’left shift’ de $x em 1 passo. Vejamos
// o que tinhamos e o que sera retornado para $y
//
// $x = 011 (3)
//
// deslocando 1 bit a esquerda teremos 110 (6)
//
// nesse momento temos:
//
// $x = 3 (nao modificamos $x)
// $y = 6
$y = $x << 1;
}
// aqui são feitas várias operações. Vamos começar
// pelas mais internas e com maior prioridade:
//
// $y^$x
//
// Aqui temos um $y xor $x. XOR - exclusive or - retornará
// os bits que estão ativos em $y e os que estão ativos
// em $x, mas não os que estão ativos em ambos: veja:
//
// $x = 011
// $y = 110
// —- 101
//
// observe que como o segundo bit estava ativo em ambos,
// ele nao estara ativo na saída. Entao após esta operação,
// o retorno será 5 (101)
//
// logo após esta operação, temos um ”not”:
//
// ~($y^$x), ou seja ~(5) ou ~5.
//
// aqui ocorre uma inversão de cada bit: Os que estão ativos
// serão desativados e os que estão desativados serão ativados:
//
// 5 - 101
// — 010
//
// o resultado desta operação então seria 2 (010)
//
// Mas tem um pequeno ”problema”: A operacao deve ser feita em
// todos os bits. Logo, ~5 = 11111111111111111111111111111010 e
// 11111111111111111111111111111010 = -6
//
// temos entao que o resultado da operacao ~($y^$x) = -6
// o resultado disso tudo é retornado por sprintf.
//
// Aproxima operação, por ordem dos operadores, é $y + (-6), ou
// seja $y + sprintf(‘%d’,~($y^$x)). Isso porque o operador ’+' tem
// precedência ante ao ’|’. Então temos
//
// $6 + (-6) = 0
//
// apos isto, temos ”$x | 0″. Aqui o os bits que estão ativos ou
// em $x ou em 0 (ou ambos, diferentemente do xor) estarão ativos na
// saída. Como 0 não tem bits ativos, o resultado da operação sera o
// própio valor de $x:
//
// $x = 011
// 0 = 000
// —- 011 (3)
//
// finalmente, temos que $y = 3
//
// ao final disso entao:
//
// $x = 3
// $y = 3
$y = $x | $y + sprintf(‘%d’,~($y^$x));// apenas exibimos um ”\n”. O $z não é utilizado mais
$z = print(“\n”);
// verificamos se $x é menor do que $y (não é)
if ($x < $y) {
$x ^= $x;
// observe que aqui não temos um else. Então esse trecho
// será executado de qualquer forma (mesmo que o if anterior
// fosse verdadeiro. Foi utilizado apenas para ”confundir” : )
} {
// Fazemos um xor de $y em $y. Lembre-se que no xor, o retorno
// são os bits que estão ativos ou em um ou em outro número, mas
// não em ambos. Como o xor está sendo feito no mesmo número, o que
// estiver ativo em um também estará ativo em outro. Logo, o retorno
// será 0 (este tipo de operação é bastante utilizada em assembly,
// quando se deseja zerar o valor de algum registrador: ”xor eax, eax”
// ”xor ebx, ebx”, …)
//
// $y = 011
// $y = 011
// —- 000
//
//
$y ^= $y;
// novamente utilizamos um bloco, que será executado de qualquer forma
} {
// verificamos se $x (3) é maior do que $y (0). Como sabemos que é,
// será exibido ’$y menor do que $x’
if ($x > $y) {
echo ‘$y menor do que $x’;
// e este trecho será ignorado : )
} else {
echo ‘$y maior do que $x’;
}
}
}
// finalmente, exibimos um último ”\n”
echo “\n”;
?>
Ao final disso, temos então:
Iniciando desafio 2
$y menor do que $x
É isso, espero que tenha aprendido um pouco sobre bitwise operations neste desafio.