Eu estava procurando uma abordagem eficiente para calcular a b (digamos a = 2
e b = 50
). Para começar, decidi dar uma olhada na implementação da Math.Pow()
função. Mas no .NET Reflector , tudo o que encontrei foi o seguinte:
[MethodImpl(MethodImplOptions.InternalCall), SecuritySafeCritical]
public static extern double Pow(double x, double y);
Quais são alguns dos recursos em que posso ver o que está acontecendo lá dentro quando chamo Math.Pow()
função?
InternalCall
com umextern
modificador (como eles parecem estar em conflito), consulte a pergunta (e as respostas resultantes) que publiquei sobre essa mesma coisa.2^x
operação sex
for inteiro, o resultado é uma operação de deslocamento. Então, talvez você possa construir o resultado usando uma mantissa de2
e um expoente dex
.Respostas:
Isso significa que o método é realmente implementado no CLR, escrito em C ++. O compilador just-in-time consulta uma tabela com métodos implementados internamente e compila a chamada para a função C ++ diretamente.
A análise do código requer o código fonte do CLR. Você pode obter isso da distribuição SSCLI20 . Foi escrito em torno do período do .NET 2.0. Encontrei as implementações de baixo nível, que
Math.Pow()
ainda são amplamente precisas para versões posteriores do CLR.A tabela de pesquisa está localizada em clr / src / vm / ecall.cpp. A seção que é relevante
Math.Pow()
é assim:A busca por "COMDouble" leva você a clr / src / classlibnative / float / comfloat.cpp. Vou poupar o código, basta dar uma olhada. Ele basicamente verifica os casos de canto e depois chama a versão do CRT
pow()
.O único outro detalhe de implementação interessante é a macro FCIntrinsic na tabela. Essa é uma dica de que o jitter pode implementar a função como intrínseca. Em outras palavras, substitua a chamada de função por uma instrução de código de máquina de ponto flutuante. O que não é o caso
Pow()
, não há instruções de FPU para isso. Mas certamente para as outras operações simples. Notável é que isso pode tornar a matemática de ponto flutuante em C # substancialmente mais rápida que o mesmo código em C ++, verifique esta resposta pelo motivo.A propósito, o código fonte do CRT também estará disponível se você tiver a versão completa do diretório vc / crt / src do Visual Studio. Você atingirá o muro
pow()
, porém, a Microsoft comprou esse código da Intel. Fazer um trabalho melhor do que os engenheiros da Intel é improvável. Embora a identidade do meu livro do ensino médio fosse duas vezes mais rápida quando eu tentei:Mas não é um substituto verdadeiro, pois acumula erro de três operações de ponto flutuante e não lida com os problemas de domínio esquisito que Pow () possui. Como 0 ^ 0 e -Infinity aumentado para qualquer poder.
fonte
pow
é notoriamente difícil de implementar com precisão, sendo uma função transcendental (consulte o Dilema do criador de tabelas ). É muito mais fácil com um poder integral.A resposta de Hans Passant é ótima, mas eu gostaria de acrescentar que, se
b
for um número inteiro,a^b
pode ser computado com muita eficiência com decomposição binária. Aqui está uma versão modificada de Henry Warren's Hacker's Delight :Ele observa que essa operação é ideal (faz o número mínimo de operações aritméticas ou lógicas) para todos os b <15. Também não há solução conhecida para o problema geral de encontrar uma sequência ótima de fatores para calcular
a^b
qualquer b que não seja um extenso procurar. É um problema NP-Hard. Então, basicamente, isso significa que a decomposição binária é a melhor possível.fonte
a
for um número de ponto flutuante.a
ser um número inteiro, mas o código sim. Como conseqüência disso, pergunto-me sobre a precisão do resultado da computação "muito eficiente" do texto.Se a versão C disponível gratuitamente
pow
for qualquer indicação, ela não se parece com o que você esperaria. Não seria de muita ajuda para você encontrar a versão .NET, porque o problema que você está resolvendo (ou seja, aquele com números inteiros) é de ordens de magnitudes mais simples e pode ser resolvido em algumas linhas de código C # com a exponenciação ao quadrado do algoritmo .fonte