MethodImplOptions.InternalCall
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:
FCFuncStart(gMathFuncs)
FCIntrinsic("Sin", COMDouble::Sin, CORINFO_INTRINSIC_Sin)
FCIntrinsic("Cos", COMDouble::Cos, CORINFO_INTRINSIC_Cos)
FCIntrinsic("Sqrt", COMDouble::Sqrt, CORINFO_INTRINSIC_Sqrt)
FCIntrinsic("Round", COMDouble::Round, CORINFO_INTRINSIC_Round)
FCIntrinsicSig("Abs", &gsig_SM_Flt_RetFlt, COMDouble::AbsFlt, CORINFO_INTRINSIC_Abs)
FCIntrinsicSig("Abs", &gsig_SM_Dbl_RetDbl, COMDouble::AbsDbl, CORINFO_INTRINSIC_Abs)
FCFuncElement("Exp", COMDouble::Exp)
FCFuncElement("Pow", COMDouble::Pow)
// etc..
FCFuncEnd()
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:
public static double FasterPow(double x, double y) {
return Math.Exp(y * Math.Log(x));
}
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.
InternalCall
com umextern
modificador (como eles parecem estar em conflito), consulte a pergunta (e as respostas resultantes) que publiquei sobre essa mesma coisa.