C/C++ Alguém sabe a resolução deste exercício? [RESOLVIDO]

1. C/C++ Alguém sabe a resolução deste exercício? [RESOLVIDO]

Yukio Mishima
TrueMishima

(usa Debian)

Enviado em 22/05/2016 - 09:58h

Olá a todos, sou noob no estudo de linguagem de programação. Em relação ao exercício abaixo, não consigo achar uma maneira para evitar o estouro. Por exemplo, se escolho tanto para base quanto para expoente o valor 5.000.000.000, dá pane no programa. Há alguma outra maneira de fazer isso sem tratar o unsigned int como uma string? Isto é, limitando a quantidade de caracteres dentro de um laço for, por exemplo?
Segue abaixo o enunciado.
Desde já agradeço a todos!

33. Implementar a função EXP com as seguintes características:
a. Recebe um valor de base e um valor de expoente como parâmetros do tipo unsigned int.
b. Recebe o endereço de uma variável, do tipo unsigned int, em cujo conteúdo será armazenado o resultado de baseexpoente.
c. Retorna 1 se foi bem sucedida e 0 se a exponenciação não pôde ser calculada devido a estouro.
d. Utiliza a característica recursiva da exponenciação:
i. Baseexp = base.baseexp-1 , exp > 0
ii. Baseexp = 1, exp ==0



  


2. Re: C/C++ Alguém sabe a resolução deste exercício? [RESOLVIDO]

Paulo
paulo1205

(usa Ubuntu)

Enviado em 22/05/2016 - 18:09h

Pela descrição que você colocou, você tem basicamente de traduzir o que está escrito para C. Não tem nem mesmo muita margem de interpretação ou de variação.


3. Código

Yukio Mishima
TrueMishima

(usa Debian)

Enviado em 23/05/2016 - 15:34h

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>

using namespace std;

unsigned int base, expoente, aux, scoAddress;

unsigned int exp(unsigned int base, unsigned int expoente, unsigned int &scoAddress){

if(expoente > 1){
if(sizeof(base*aux) > sizeof(4))
return 0;
else
exp(base*aux, expoente-1, scoAddress=base*aux);
}


return 1;
}

int main(){

cout << "Base:" << endl;
scanf("%u", &base);
aux=base;
cout << "Expoente:" << endl;
scanf("%u", &expoente);
scoAddress=exp(base, expoente, scoAddress);
printf("%u", scoAddress);

cout << endl << endl;
system("pause");
return 0;
}


Obrigado pela atenção.


4. Re: C/C++ Alguém sabe a resolução deste exercício?

Paulo
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.

    aux=base; 


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. ;)

    return 0;
}



5. Re: C/C++ Alguém sabe a resolução deste exercício? [RESOLVIDO]

Paulo
paulo1205

(usa Ubuntu)

Enviado em 24/05/2016 - 19:42h

Fiz algumas edições em minha resposta anterior, para deixá-la ainda mais completa. Se possível reexamine-a.


6. Reformulando código ...

Yukio Mishima
TrueMishima

(usa Debian)

Enviado em 28/05/2016 - 18:50h

Boa noite Paulo, estava lendo tua resposta e logo pensei: "ele falou aramaico comigo." ... kkkkkkkkkkkk :-p .
Meus conhecimentos em relação a termos matemáticos são bem limitados.
Dei uma googleada e por fim fiz as devidas modificações.
Além de não pagar multa, juro que também não mesclo mais funções de C com C++. kkkkkkk
Desculpe a demora ao responder.
Vou ver o que posso melhorar aqui.
Muito obrigado!


#include <iostream>
#include <cstdlib>

using namespace std;
unsigned int exp(unsigned int bas, unsigned int expo, unsigned int *address){

if(expo>1){
*address=bas*(*address);
exp(bas, expo-1, address);
}

return 1;
}

int main(){
unsigned int base, expoente, *endereco;

cout << "Base:" << endl;
cin >> base;
cout << "Expoente:" << endl;
cin >> expoente;
endereco=&base;
exp(base, expoente, endereco);
cout << endl;

return 0;
}



7. Re: C/C++ Alguém sabe a resolução deste exercício? [RESOLVIDO]

Paulo
paulo1205

(usa Ubuntu)

Enviado em 28/05/2016 - 21:11h

Ainda não está correto.

A maneira certa de usar a função seria a seguinte:

unsigned base, expoente, result;

/* ... define base e expoente ... */

if(power(base, expoente, &result))
cout << base << " elevado a " << expoente << " é igual a " << result << ".\n";
else
cerr << "Não foi possível calcular a potência.\n";


Note que o seu código não faz bem isso. Do jeito como você escreveu a função, o conteúdo inicial do ponteiro (terceiro parâmetro) acaba sendo fundamental para o resultado final. Além disso, você não tratou o caso de expoente igual a zero nem a possibilidade de overflow, embora tais situações estivessem no enunciado original.






Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts