Greg Hewgill e IllidanS4 deram um link com uma excelente explicação matemática. Vou tentar resumir aqui para aqueles que não querem entrar muito em detalhes.
Qualquer função matemática, com algumas exceções, pode ser representada por uma soma polinomial:
y = f(x)
pode ser exatamente transformado em:
y = a0 + a1*x + a2*(x^2) + a3*(x^3) + a4*(x^4) + ...
Onde a0, a1, a2, ... são constantes . O problema é que para muitas funções, como raiz quadrada, para valor exato essa soma tem um número infinito de membros, ela não termina em algum x ^ n . Mas, se pararmos em algum x ^ n , ainda teremos um resultado com alguma precisão.
Então, se tivermos:
y = 1/sqrt(x)
Neste caso particular, eles decidiram descartar todos os membros polinomiais acima do segundo, provavelmente por causa da velocidade de cálculo:
y = a0 + a1*x + [...discarded...]
E agora chegou a tarefa de calcular a0 e a1 para que y tenha a menor diferença do valor exato. Eles calcularam que os valores mais apropriados são:
a0 = 0x5f375a86
a1 = -0.5
Então, quando você coloca isso na equação, você obtém:
y = 0x5f375a86 - 0.5*x
Que é a mesma linha que você vê no código:
i = 0x5f375a86 - (i >> 1);
Edit: na verdade aqui y = 0x5f375a86 - 0.5*x
não é o mesmo que i = 0x5f375a86 - (i >> 1);
mudar o float como inteiro não só divide por dois, mas também divide o expoente por dois e causa alguns outros artefatos, mas ainda se resume a calcular alguns coeficientes a0, a1, a2 ....
Nesse ponto, eles descobriram que a precisão desse resultado não é suficiente para o propósito. Então, eles também fizeram apenas uma etapa da iteração de Newton para melhorar a precisão do resultado:
x = x * (1.5f - xhalf * x * x)
Eles poderiam ter feito mais algumas iterações em um loop, cada uma melhorando o resultado, até que a precisão necessária seja alcançada. É exatamente assim que funciona na CPU / FPU! Mas parece que apenas uma iteração foi suficiente, o que também foi uma bênção para a velocidade. A CPU / FPU faz quantas iterações forem necessárias para atingir a precisão do número de ponto flutuante no qual o resultado é armazenado e tem um algoritmo mais geral que funciona para todos os casos.
Resumindo, o que eles fizeram é:
Use (quase) o mesmo algoritmo que CPU / FPU, explore a melhoria das condições iniciais para o caso especial de 1 / sqrt (x) e não calcule todo o caminho para a precisão CPU / FPU irá para, mas pare antes, portanto ganhando em velocidade de cálculo.