Como fazer o inverso da raiz quadrada

Antonio Rodrigues Neto*
Especial para a Página 3 Pedagogia & Comunicação

Imagine abrir um livro de matemática e encontrar a expressão abaixo:

Como fazer o inverso da raiz quadrada

Lemos que x é a raiz sexta de 729, sendo que, nesse número, está sendo aplicada uma operação conhecida como radiciação. A radiciação é a operação inversa da potenciação - e pode ser interpretada como conseqüência de uma potenciação em que não conhecemos o valor da base.

Para ilustrar melhor a relação entre essas duas operações inversas utilizarei a pergunta que gerou a curiosa expressão no inicio deste texto: qual o número que, elevado a seis, é igual a 729? A álgebra - que é sempre um bom recurso para esse tipo de pergunta - transforma essa pergunta em uma equação, utilizando a estratégia de representar, por meio de letras, as quantidades ou as medidas desconhecidas:
Como fazer o inverso da raiz quadrada
Resolver uma equação é calcular o valor da incógnita proposta pelo problema. Para isso são aplicados artifícios e manobras do pensamento matemático que, no nosso caso, terão de envolver as propriedades da potenciação. Uma dessas manobras é a da potência elevada a uma outra potência. Em vez de aplicarmos duas vezes o conceito de potenciação (exemplo a), simplificamos o caminho multiplicando diretamente os expoentes (exemplo b):
Como fazer o inverso da raiz quadrada

Como fazer o inverso da raiz quadrada

Com essa propriedade, podemos construir um caminho para resolver a nossa equação do x elevado a seis que é igual a 729:


Como fazer o inverso da raiz quadrada

Observando o expoente 6, somos instigados, pela propriedade já mostrada, a multiplicar o expoente seis pelo seu inverso, a fim de obter resultado igual a 1. Para que isso ocorra, temos de elevar a potência do primeiro membro, x elevado a seis, a um sexto. Essa iniciativa constrói um caminho confortável para acharmos o valor de x:


Como fazer o inverso da raiz quadrada

O desafio passa a ser o de eliminar o expoente do primeiro membro sem causar a desigualdade na equação. Com essa preocupação, tudo o que for feito no primeiro membro terá que ser feito no segundo membro, e vice-versa. É um dos princípios que mantém a igualdade de uma equação e que organiza caminhos para a sua resolução. Dessa forma, elevamos os dois membros da nossa equação a um sexto:


Como fazer o inverso da raiz quadrada

Feito isso, fazemos a fatoração de 729. Já que estamos trabalhando com as propriedades da potenciação, tudo que for escrito com expoente servirá de suporte nas aplicações dessas propriedades. O resultado da fatoração de 729 é três elevado a seis:


Como fazer o inverso da raiz quadrada
Assim, aplicamos novamente a propriedade da potenciação de multiplicar os expoentes, com as respectivas simplificações, obtendo o valor simplificado de x:
Como fazer o inverso da raiz quadrada
Um outro caminho é realizar primeiro a fatoração - e depois as manobras com os expoentes. Qual é o número que, elevado a seis, é igual a 16?
Como fazer o inverso da raiz quadrada

Percebemos que, no exemplo acima, temos a simplificação do expoente de 4/6 para 2/3. Um resultado que mantém o expoente fracionário, na condição deste não poder mais ser simplificado. Esse expoente fracionário conduz a uma importante informação, que auxilia na interpretação da radiciação. O expoente fracionário pode ser representado de uma outra forma. A matemática possui esses detalhes em sua linguagem:


Como fazer o inverso da raiz quadrada

O denominador do expoente fica na forquilha do radical (símbolo da operação) e será chamado de índice. Já o numerador fica como sendo o expoente do número que está dentro da raiz, que é conhecido por radicando.

Então, no exemplo acima, o 4 é o radicando, o 3 é o índice e o resultado da operação, representado por x, é a raiz. A operação não sendo exata, como neste exemplo, significará que não foi possível transformar, por simplificações, o expoente fracionário em um número inteiro. Dessa forma, ele se manterá fracionário e poderemos deixá-lo indicado no radical, como acabamos de descrever.

A raiz quadrada de 2 ou a raiz cúbica de 7 são alguns dos infinitos exemplos desses casos. Eles irão gerar um novo tipo de número, que será classificado como irracional. Um tema para ser aprofundado em uma outra ocasião.

*Antonio Rodrigues Neto, professor de matemática no ensino fundamental e superior, é mestre em educação pela USP e autor do livro "Geometria e Estética: experiências com o jogo de xadrez" pela Editora da UNESP.

Talvez um dos melhores exemplos para isso é esse pequeno pedaço do código pertencente ao game Quake III, que vocês podem ver logo aí em cima.

Seu objetivo é calcular o inverso da raiz quadrada. Por exemplo: y = 1/√x. Na computação, é utilizada para normalização de vetores. Colocando em termos simples: ela deixa vetores com o comprimento de valor um, afim de evitar comportamentos estranhos nas luzes e sombras presentes nos jogos 3D.

Na linguagem que tenho mais domínio, o Javascript, essa operação poderia ser traduzida desta forma:

const y = 1 / Math.sqrt(x);

Claramente as linguagens de programação melhoram muito desde então, se está tudo mais simples, não é mesmo?

Mas quem implementou tal função não queria (esse tipo de) simplicidade.

Um código legível é sempre interessante, mas não adianta algo simples que não atende a necessidade presente.

O inverso da raiz quadrada é uma operação lenta se implementada de forma usual, e, como se tratava de um game rápido, com muitas mudanças gráficas simultâneas, era mais vital que os vetores fossem normalizados em alta velocidade.

Para tanto, algumas técnicas bastante interessantes foram incluídas no código.

A bit about bits.

Sabemos que os números armazenados pelo computador obedecem o padrão binário. Isso quer dizer que cada casa unitária tem a base dois, diferente de nosso sistema decimal, cuja base é dez. Ademais, positivos e negativos também serão representados por zeros e uns, respectivamente. Cada um desses zeros e uns é chamado de bit, e podemos ler sua interpretação abaixo:

Binário || Representação matemática || Resultado 1 10 || - (1*2 + 0*1) || -2 0 100 || + (1*4 + 0*2 + 0*1) || 4 1 101 || - (1*4 + 0*2 + 1*1) || -5 0 1010 || + (1*8 + 0*4 + 1*2 + 0*1) || 10

Agora eu lhe proponho, meu caro leitor, que imagine um computador fazendo a mais simples conta de divisão. Temos um computador utilizando quatro bits para representar o dez, e mais dois bits para representar o dois, além de todos os bits necessários para representar uma conta de divisão. É bastante memória sendo utilizada em algo que, para um cérebro humano, parece claro, não?

Agora imagine números da grandeza limite de uma long, variável declarada na primeira linha da função acima, que pode armazenar informações de até 32 bits. Imagine uma conta como essa:

2.147.483.647 / 321.429

Espero que você consiga entender que, naturalmente, divisão é a mais demorada operação básica a ser computada. Ainda é extremamente rápida para os padrões humanos, porém digo-lhe, sem sombra de dúvida, que era lenta demais para atender às necessidades dos programadores de Quake III, que decidiram por algo diferente, mais otimizado.

Bit hacking.

Responda rápido: quanto é um milhão e meio dividido por duzentos e cinquenta mil? Lento demais. Garanto-lhe, porém, que a resposta seria mais fácil se você colocasse esses inteiros no papel:

1.500.000/250.000

Seu primeiro passo, naturalmente, seria cortar os zeros. Você não vai perder tempo dividindo desde lá de trás, vai? Mas, meu caro, você está dividindo. A cada zero que você elimina, na prática, o número é dividido por dez. E digamos que você seja temerário e deseja ir além dos zeros, mas cortar o cinco também:

15/2

Hoje é dia de loucura. Hoje dividimos quinze por dois e isso vai dar 7.5. A variação é imensa da resposta correta, que é 6, mas, de qualquer forma, foi possível ter uma ideia do que a conta daria - sua ordem de grandeza, por exemplo - e, frequentemente, uma aproximação pode ser o suficiente.

Agora retorne à tabelinha de binários e suas representações. Veja que, a cada zero retirado no fim do número, ele é dividido por dois. Obviamente, a cada zero adicionado, ele será multiplicado por dois. Se for ímpar, a conta será arredondada, mas digamos que isso não faz diferença para nós.

Nesse momento você já deve ter entendido o que quero dizer. Se extrema precisão não é aquilo que procuramos, mas velocidade, não precisamos gastar a memória e o processamento do computador com a complexidade de uma operação de divisão. Basta descobrir quantos zeros ou uns vamos cortar, e o ganho é exponencial desde as mais simples operações.

Antes, para realizar a operação de dez (1010) dividido por dois (10), utilizávamos ao menos seis bits, agora podemos simplesmente desligar um bit do dez, transformando-o em cinco (101). Eis o que o operador ( >> 1 ) fez na linha com palavrão, simplesmente jogou os bits para a direita, a fim de dividi-los por dois.

Esta era a simplicidade que o programador buscava.

Ok, agora entendo uma linha do código. Grande coisa.

Por isso mesmo que, na Parte Dois: Evil Bit Hacking, entraremos em um novo mundo de loucura, mergulhando ainda mais em programação de baixo nível.

Para aqueles que tiveram a coragem de me acompanhar até aqui, darei um spoiler como agradecimento: Agora já sabemos que devemos cortar bits, certo? Mas existe um detalhe sombrio... pretendemos cortar esses bits de um número decimal do tipo float, e eles não foram feitos para terem seus bits abusados dessa maneira porque não são como os outros números binários. Isso mesmo! Diferente de tudo o que disse até agora, eles não armazenam os dados da mesma forma que expliquei ali em cima.

Agora resta saber: como um programador passa a perna em seu próprio computador?

Veja mais nos próximos capítulos...