paulo1205
(usa Ubuntu)
Enviado em 23/05/2016 - 17:41h
TrueMishima escreveu:
Olá, trata-se de um exercício de recursividade. O problema é quando eu digito tanto um expoente quanto uma base com valores que transbordam o programa sempre acaba dando pau. Até agora eu elaborei isto:
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
Como você parece estar usando C++, não misture cabeçalhos de C com os de C++. Para recursos de biblioteca herdados do C, use includes na forma <cHEADER> em lugar de <HEADER.h>.
using namespace std;
unsigned int base, expoente, aux, scoAddress;
Você provavelmente não quer usar variáveis globais no seu programa. Em particular, essa variável
aux é nociva, e você tem de eliminá-la.
unsigned int exp(unsigned int base, unsigned int expoente, unsigned int &scoAddress){
EDIT: O enunciado dizia que a função deveria receber um endereço. Para mim, isso soa como se o terceiro argumento tivesse, obrigatoriamente e explicitamente, de ser um ponteiro.
Você usou referência em vez de ponteiro. Referências se comportam de modo semelhante ao uso implícito de ponteiros, sem a necessidade de usar os operadores
& para obter o endereço de dados reais ou
* para chegar ao dado real a partir do endereço. Como o enunciado parece apontar no sentido de ser explícito, acho que sua solução pode não ser aceitável.
Além disso, se você usar ponteiros, o uso confuso que você faz mais abaixo (ver explicação também abaixo) provavelmente teria sido evitado.
Além do mais, como você está usando C++ e o valor de retorno indica uma condição de verdadeiro ou falso, possivelmente você poderia usar
bool como tipo de retorno, em lugar de
unsigned int;
if(expoente > 1){
if(sizeof(base*aux) > sizeof(4))
Esse uso de
sizeof está errado.
sizeof olha apenas para os tipos de dados envolvidos, não para os valores (tanto é que a expressão é avaliada durante a compilação, não durante a execução do programa). No teste acima, você está vendo se o tamanho de um inteiro sem sinal (que é o tipo da expressão
base*aux) é maior do que o tamanho de um inteiro com sinal (que é o tipo da expressão
4); como os dois tamanhos são iguais, seu teste será sempre falso.
O que você quer testar é se
A*B produz um resultado
C com
overflow. Uma forma de testar isso é dividir
C por
A, e ver se o quociente é exatamente igual a
B e se o resto da divisão é zero. Para tanto, você pode querer usar a função
div, declarada em <cstdlib>.
EDIT (para dar cola): Outro jeito é lembrar que o número de dígitos (ou bits) ocupados por um determinado número é proporcional ao logaritmo desses número, e também que o logaritmo de um produto é igual a soma dos logaritmos de cada fator. Assim, se
log2(A) (logaritmo na base 2, que, sendo
A inteiro, efetivamente conta quantos bits são ocupados por
A) somado a
log2(B) for menor do que o número de bits do tipo de dados usado para representar o produto, então o resultado certamente será válido.
return 0;
else
exp(base*aux, expoente-1, scoAddress=base*aux);
Aqui a variável global
aux é usada de maneira nefasta duas vezes. E, para completar o contrassenso, o valor dela nem é definido dentro da função ou como parte de seus parâmetros.
EDIT: O uso do terceiro argumento também está confuso. Como a função foi declarada para recebê-lo por referência não-constante, é de se esperar que a função o modifique. Contudo, você faz uma atribuição de valor que acontece antes da efetiva chamada à função, que vai depois modificar o valor de novo. Como, porém, a variável passada por referência só é usada nessa linha da função, a atribuição que foi feita antes da chamada acontecer se revela completamente inútil. E o compilador não teria como prever isso, e consequentemente otimizar o código, porque o fluxo de execução depende (ou deveria depender, se a condição do
if acima estivesse certa) dos valores da base e do expoente.
Se você tivesse usado ponteiros (ver discussão acima), essa atribuição despropositada possivelmente ficaria mais evidente, pois haveria duas expressões diferentes (ainda que numa só linha e dentro da chamada à função) para fazer o cálculo do valor e guardá-lo na memória indicada pelo ponteiro, e para obter de novo o endereço a ser passado à função. (Mas não tente nem descobrir como fazer isso, porque a função, como está, está errada de qualquer forma. É melhor gastar seu tempo corrigindo-a.)
}
return 1;
}
int main(){
cout << "Base:" << endl;
scanf("%u", &base);
Não é propriamente um erro, mas por que essa mistura de I/O ao estilo de C com a ao estilo C++? A não ser que haja alguma boa razão para fazê-lo, procure usar consistentemente apenas um estilo.
Eis aí: um elemento estranho à função, mas que é fundamental para que a função funcione.
Não faça isso. Se a função precisar de auxiliares, deixe-os internos à função. No seu caso, nem mesmo precisa, pois seu auxiliar é a própria base, que já é argumento da função, e que não vai ser alterada no interior da função (depois que ela for devidamente corrigida).
cout << "Expoente:" << endl;
scanf("%u", &expoente);
scoAddress=exp(base, expoente, scoAddress);
Notou que há na expressão acima dois lugares em que o valor de
scoAddress é modificado? Para você saber, primeiro ele é alterado dentro da função, durante sua execução, e, depois que ela retorna, o que quer que tenha sido gravado será sobrescrito com o valor retornado pela função.
Só que o valor de retorno, como você deve se lembrar, não é o da exponenciação, mas sim um sinalizador de se houve overflow ou não. Então, no fim das contas, você calcula (ou tenta calcular) uma potência, e o resultado não fica guardado em lugar nenhum!
printf("%u", scoAddress);
cout << endl << endl;
system("pause");
Toda vez que alguém usa
system("pause"), tal pessoa deveria ser obrigada a pagar uma multa. ;)