Qual é a maneira mais eficiente dada para elevar um número inteiro à potência de outro número inteiro em C?
// 2^3
pow(2,3) == 8
// 5^5
pow(5,5) == 3125
c
algorithm
math
exponentiation
Doug T.
fonte
fonte
int
s real (e não a uma classe int enorme), muitas chamadas para o ipow transbordam. Isso me faz pensar se há uma maneira inteligente de pré-calcular uma tabela e reduzir todas as combinações que não transbordam para uma simples pesquisa de tabela. Isso exigiria mais memória do que a maioria das respostas gerais, mas talvez seja mais eficiente em termos de velocidade.pow()
não é uma função seguraRespostas:
Exponenciação ao quadrado.
Este é o método padrão para realizar exponenciação modular para grandes números em criptografia assimétrica.
fonte
while (exp)
eif (exp & 1)
porwhile (exp != 0)
eif ((exp & 1) != 0)
respectivamente.unsigned exp
, ou então lidar com o negativoexp
corretamente.n*n*n*n*n*n*n*n
usa 7 multiplicações. Em vez dissom=n*n
, esse algoritmo calcula , entãoo=m*m
,p=o*o
ondep
= n ^ 8, com apenas três multiplicações. Com grandes expoentes, a diferença no desempenho é significativa.Observe que a exponenciação ao quadrado não é o método mais ideal. Provavelmente é o melhor que você pode fazer como método geral que funciona para todos os valores de expoente, mas para um valor específico de expoente pode haver uma sequência melhor que precise de menos multiplicações.
Por exemplo, se você quiser calcular x ^ 15, o método de exponenciação ao quadrado fornecerá:
Este é um total de 6 multiplicações.
Acontece que isso pode ser feito usando "apenas" 5 multiplicações via exponenciação da cadeia de adição .
Não há algoritmos eficientes para encontrar essa sequência ótima de multiplicações. Da Wikipedia :
fonte
Se você precisar aumentar 2 para uma potência. A maneira mais rápida de fazer isso é mudar a potência.
fonte
2 ** 0 == 1 << 0 == 1
Aqui está o método em Java
fonte
fonte
pow(1, -1)
não sai do intervalo de int, apesar de um expoente negativo. Agora que alguém trabalha por acidente, como fazpow(-1, -1)
.Se você deseja obter o valor de um número inteiro para 2 elevado ao poder de algo, é sempre melhor usar a opção shift:
pow(2,5)
pode ser substituído por1<<5
Isso é muito mais eficiente.
fonte
power()
função para trabalhar somente com números inteirosComplexidade = O (log (exp))
power()
função para trabalhar para exp negativa e base flutuante .Complexidade = O (log (exp))
fonte
float
no segundo bloco de código apresentado (considere mostrar comopower(2.0, -3)
é computado).negative exp and float base
solução? por que usamos temp, separamos exp por 2 e verificamos exp (par / ímpar)? obrigado!Um caso extremamente especializado é que, quando você precisa dizer 2 ^ (- x para y), onde x, é claro que é negativo e y é muito grande para alterar um int. Você ainda pode fazer 2 ^ x em tempo constante apertando com um flutuador.
Você pode obter mais potências de 2 usando um duplo como o tipo base. (Muito obrigado aos comentaristas por ajudarem a corrigir esta postagem).
Há também a possibilidade de que, aprendendo mais sobre flutuadores IEEE , outros casos especiais de exponenciação possam se apresentar.
fonte
Apenas como acompanhamento de comentários sobre a eficiência da exponenciação por quadratura.
A vantagem dessa abordagem é que ela é executada no tempo de log (n). Por exemplo, se você fosse calcular algo enorme, como x ^ 1048575 (2 ^ 20 - 1), você só precisa passar pelo loop 20 vezes, e não 1 milhão + usando a abordagem ingênua.
Além disso, em termos de complexidade do código, é mais simples do que tentar encontrar a seqüência mais ótima de multiplicações, como a sugestão de Pramod.
Editar:
Acho que devo esclarecer antes que alguém me marque o potencial de estouro. Essa abordagem pressupõe que você tenha algum tipo de biblioteca enorme.
fonte
Atrasado para a festa:
Abaixo está uma solução que também lida com
y < 0
o melhor possível.intmax_t
para o alcance máximo. Não há provisão para respostas que não se encaixemintmax_t
.powjii(0, 0) --> 1
o que é um resultado comum para este caso.pow(0,negative)
, outro resultado indefinido, retornaINTMAX_MAX
Esse código usa um loop
for(;;)
para sempre para evitar obase *= base
comum final em outras soluções em loop. Essa multiplicação é 1) não necessária e 2) pode estarint*int
excedendo, o que é UB.fonte
powjii(INT_MAX, 63)
causa UB embase *= base
. Considere verificar se é possível multiplicar ou vá para não assinado e deixe-o passar.exp
assinado. Isso complica o código devido à situação ímpar em que(-1) ** (-N)
é válido, e qualquerabs(base) > 1
será0
para valores negativos deexp
, portanto, é melhor deixar de assinar e salvar esse código.y
como assinado, não é realmente necessário e traz as complicações que você comentou, mas a solicitação da OP foi específicapow(int, int)
. Portanto, esses bons comentários pertencem à pergunta do OP. Como o OP não especificou o que fazer no estouro, uma resposta errada bem definida é apenas marginalmente melhor que o UB. Dada a "maneira mais eficiente", duvido que o OP se preocupe com o OF.solução mais genérica considerando exponenet negativo
fonte
pow(i, INT_MIN)
poderia ser um loop infinito.pow(i, INT_MIN)
não excede o número inteiro. A atribuição desse resultadotemp
certamente pode transbordar, potencial causando o fim dos tempos , mas vou me contentar com um valor aparentemente aleatório. :-)Mais uma implementação (em Java). Pode não ser a solução mais eficiente, mas o número de iterações é o mesmo da solução exponencial.
fonte
Eu uso recursivo, se o exp for par, 5 ^ 10 = 25 ^ 5.
fonte
Além da resposta de Elias, que causa Comportamento indefinido quando implementado com números inteiros assinados e valores incorretos para entrada alta quando implementada com números inteiros não assinados,
aqui está uma versão modificada da exponenciação por esquadro que também funciona com tipos inteiros assinados e não fornece valores incorretos:
Considerações para esta função:
Se ocorrer algum transbordamento ou encapsulamento,
return 0;
Eu usei
int64_t
, mas qualquer largura (assinada ou não) pode ser usada com poucas modificações. No entanto, se você precisa usar um tipo inteiro não de largura fixa, você terá de mudarSQRT_INT64_MAX
por(int)sqrt(INT_MAX)
(no caso de usarint
) ou algo semelhante, que deve ser otimizado, mas é mais feio, e não uma expressão C constante. Também converter o resultado desqrt()
para umint
não é muito bom por causa da precissão de ponto flutuante no caso de um quadrado perfeito, mas como não conheço nenhuma implementação em queINT_MAX
- ou o máximo de qualquer tipo - seja um quadrado perfeito, você pode viver com isso.fonte
Eu implementei um algoritmo que memoriza todos os poderes computados e os utiliza quando necessário. Assim, por exemplo, x ^ 13 é igual a (x ^ 2) ^ 2 ^ 2 * x ^ 2 ^ 2 * x onde x ^ 2 ^ 2 foi retirado da tabela em vez de computá-lo novamente. Isso é basicamente a implementação da resposta @Pramod (mas em C #). O número de multiplicação necessário é Ceil (Log n)
fonte
public
? 2 funções com o mesmo nome? Esta é uma pergunta C.Meu caso é um pouco diferente, estou tentando criar uma máscara a partir de uma fonte, mas pensei em compartilhar a solução que encontrei de qualquer maneira.
Obviamente, ele só funciona para potências de 2.
fonte
#define MASK(e) (((e) >= 64) ? -1 :( (1 << (e)) - 1))
, de modo que pode ser calculado em tempo de compilaçãoCaso você saiba o expoente (e é um número inteiro) no tempo de compilação, você pode usar modelos para desenrolar o loop. Isso pode ser mais eficiente, mas eu queria demonstrar o princípio básico aqui:
Encerramos a recursão usando uma especialização de modelo:
O expoente precisa ser conhecido em tempo de execução,
fonte
(c != c++) == 1