Perdoe a ingenuidade que será óbvia na maneira como faço essa pergunta, bem como no fato de estar fazendo.
Os matemáticos normalmente usam , pois é a base mais simples / mais agradável da teoria (devido ao cálculo). Mas os computadores parecem fazer tudo em binário, então é mais rápido em uma máquina calcular do que ?2**x
Math::exp(x)
binary-arithmetic
numerical-analysis
numeral-representations
isomorfismos
fonte
fonte
Respostas:
Como esse é o CS e não o Stackoverflow, vou assumir que você está fazendo uma pergunta sobre análise numérica e (para simplificar) o ponto flutuante IEEE-754 em particular. Nesse caso, a resposta à sua pergunta depende em parte do que você quer dizer com "mais fácil" e em parte nos detalhes do sistema.
Nenhuma CPU moderna que eu conheço possui uma instrução construída, que faz exatamente o que você esperaria para a operação (que daqui em diante chamaremos , seu nome usual em C) ou 2 x ( ). Ambos são implementados usando funções de biblioteca.ex 2x
exp
exp2
Como é o caso de todos os métodos numéricos para operações transcendentais, há alguns casos especiais a serem considerados:
No entanto, há outra coisa que torna o problema um pouco menos complicado: o domínio útil é bem pequeno. Para binary32, subfluxax<−104 x>88.7
exp(x)
se ou mais e transborda se x > 88,7 ou menos. Invulgarmente para operações transcendentais, também podemos ignorar o caso subnormal, pois é indistinguível de se é subnormal. Todas as opções acima também são verdadeiras , exceto que o domínio é um pouco diferente.exp(x)
1.0
x
exp2
Sua intuição está certa em que a maioria das implementações calcula . No entanto, o custo dessa multiplicação por 1ex=2x/ln2 é trivial comparado ao resto da computação. Um método típico usa uma tabela pré-computada comelementosK:1ln2 K
exp2
onde é a parte inteira de x , a tabela T contém valores de 2 j / K para todos os j no intervalo [ 0 , K ) e P é uma aproximação polinomial de 2 x (o quártico é suficiente para binário32) no intervalo [ 0 , 1n x T 2j/K j [0,K) P 2x . Aparte2né barata, pois está apenas manipulando o expoente. Té uma tabela de pesquisa. Portanto,Pé provavelmente a parte mais cara da operação.[0,1K) 2n T P
Devo salientar por completo que as FPUs Intel x86 incluem uma instrução chamada2x−1 x [−1,1]
f2xm1
, que calcula por x no intervalo [ - 1 , 1 ] . No entanto, em uma CPU moderna, essa é uma instrução bastante cara e sem pipeline, e você é altamente desencorajado de usá-la. Como observa corretamente a seção 3.8.5 do Intel Optimization Reference Manual :Edit: Foi indicado nos comentários que devo explicar algumas das novas terminologias usadas no IEEE 754-2008. Parte da linguagem mudou desde 1985 e 1987, e a maioria das pessoas está muito mais familiarizada com o velho jargão.
Os termos "binary32" e "binary64" são os novos nomes para números de ponto flutuante binário de 32 e 64 bits, que o antigo padrão chamou de "único" e "duplo", respectivamente.
O termo "número subnormal" substitui o termo anterior "número desnormal" ou "número desnormalizado" .
fonte
2**x
<<
1 << x
fonte
x
não for um número inteiro (digamos20.75
), você definiria a mantissa como2
e o expoente como o valor arredondadox
como a estimativa mais precisa (representação precisa não sendo possível). O que também é muito mais rápido que o pow.Se
2**x
for uma função em números inteiros, concordo com a resposta de Stephen, o deslocamento é mais barato. Mas normalmente vejo isso como2^x
e**
para indicar exponenciação de ponto flutuante. Para este caso, eu esperaria um desempenho semelhante entre**
e^
uma vez que ambosexp
epow
(a operação subjacente para**
) são operações de aproximação transcendental.fonte
**
era considerado sinônimo da versão de ponto flutuante (e, bobo, eu tinha esquecido que as duas seriam diferentes).Como 2 ^ x = e ^ (x * ln 2) e e ^ x = 2 ^ (x * log2 (e)), você não esperaria muita diferença.
Para x próximo a zero, usualmente se usaria um polinômio e ^ x = 1 + x + x ^ 2/2 + x ^ 3/6 ..., bem otimizado para cortar o mais rápido possível, mantendo pequeno o erro de arredondamento . Claramente 2 ^ x é um pouquinho, um pouquinho mais lento para calcular. "x próximo a 0" normalmente seria valores de x em que sqrt (1/2) <= e ^ x <= sqrt (2). A restrição do intervalo de x garante que o grau polinomial não precise ser escolhido muito alto.
Para x maior, usualmente calcularíamos 2 ^ x deixando x = x '+ x' ', onde x' é um número inteiro e -0,5 <= x '' <= 0,5. 2 ^ x 'seria então calculado construindo um número de ponto flutuante com o padrão de bits correto e 2 ^ x' 'usando o método e ^ x para x pequeno. Aqui, 2 ^ x é um pouco mais rápido. Além disso, se x é muito amplo (digamos x = 100,3), apenas multiplicar x por log2 (e) introduziria um erro de arredondamento inaceitável (porque há muito menos bits fracionários), portanto, é necessário mais cuidado.
E, esperançosamente, uma boa função de biblioteca cuidaria para que sempre que x <= y, e ^ x <= e ^ y e 2 ^ x <= 2 ^ y, não importassem quais fossem os erros de arredondamento. Conseguir esse tipo de coisa pode ser complicado.
fonte
Você precisa entender que a matemática em um computador é feita de maneiras diferentes por diferentes softwares, com esperança de obter respostas consistentes. Olhando para a maioria dos softwares, acho que os computadores se comportam como bem - computadores e calcularão a resposta até mesmo para 0 ^ 0. O problema é que casos especiais envolvem "reconhecimento", o que não ocorre de graça em computadores digitais. Isso significa que somente nos casos em que ter a resposta acelerará as coisas "o máximo" ocorrerá a otimização. Mas, nesses casos, ocorrerá extremamente bem. Observe também que vários reconhecimentos diferentes podem ter que ser feitos para obter a resposta certa. Isso é chamado de níveis de otimização de velocidade e isso ocorreu na extensão profissional máxima na base da maioria dos softwares chamados GNU "C". Isso ocorre porque aqui são usadas pequenas diferenças no tempo de execução de software para software e de máquina para máquina como valores de aceitação da qualidade. Em outros intérpretes, normalmente, apenas se um "sinalizador zero" ocorrer como efeito colateral dos cálculos anteriores acelerará o reconhecimento. como 0 * x => C0.
fonte