Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: prometheus48 en 28 Enero 2012, 14:36 pm



Título: Codigo fuente de la funcion pow de math.h?
Publicado por: prometheus48 en 28 Enero 2012, 14:36 pm
Hola,

Me gustaria hacer un programa que hiciera eso, elevar un numero base a una potencia, pero sin utilizar un bucle o la libreria math.h .

¿Alguien tiene el source code de la funcion pow?

¿O alguien sabe como hacerlo?

Salu2!


Título: Re: Codigo fuente de la funcion pow de math.h?
Publicado por: eleon en 28 Enero 2012, 20:07 pm
No sé cuál será el código en la librería "math.h" pero es tan sencillo como un bucle:

Código
  1. #include <iostream>
  2. using namespace std;
  3.  
  4. int main()
  5. {
  6. int x1, exponente, resultado;
  7.  
  8. cout << "Base: ";
  9. cin >> x1;
  10. cout << endl << "Exponente: ";
  11. cin >> exponente;
  12.  
  13. resultado = x1;
  14.  
  15. if (exponente = 0) resultado = 1;
  16. else if (exponente = 1) resultado = x1;
  17. else {
  18. for (int i = 1; i < exponente; i++)
  19. {
  20. resultado *= x1;
  21. }
  22.  
  23. if (exponente < 0) resultado = 1 / resultado; //Si el exponente es negativo...
  24.  
  25. cout << endl << "Resultado: " << resultado;
  26.  
  27. return 0;
  28. }
  29. }

Ahora mismo no tengo compilador para probarlo, pero creo que no tiene ningún error. Saludos.

Edito: Vale, me doy cuenta de que faltaría modificar el matiz para un exponente negativo, voy a ver como sería y comento.

Edito 2: Corregido, si el exponente es negativo basta con dividir 1 entre el resultado.


Título: Re: Codigo fuente de la funcion pow de math.h?
Publicado por: Akai en 29 Enero 2012, 00:11 am
@eleon: un pequeño apunte. A parte de utilizar enteros con lo cual dividir 1 entre el resultado de la potencia te va a dar un 0 como una casa, aportas un código que lo hace utilizando un bucle, cosa que prometheus48 intentaba evitar.


@prometheus48:

El source code de la función pow lo encontrarás entre el código fuente del compilador que utilices.
Por otro lado, suena a ejercicio de clase o algo por el estilo. Para qué querrías hacer una potencia sin utilizar un bucle?
Si eso mírate recursividad.


Título: Re: Codigo fuente de la funcion pow de math.h?
Publicado por: Xandrete en 29 Enero 2012, 00:59 am
Edito: Vale, me doy cuenta de que faltaría modificar el matiz para un exponente negativo, voy a ver como sería y comento.

Edito 2: Corregido, si el exponente es negativo basta con dividir 1 entre el resultado.

Y te faltaría también el caso general de un exponente real. Lo cierto es que no me voy a currar una explicación muy detallada si no tengo la seguridad de que de verdad te interesa el caso general del exponente real (en mi solución entrarían polinomios de Taylor, por ejemplo, y no es algo sobre lo que me apetezca escribir después de medianoche sin la certeza de que no se lo van a pasar por el forro, xD). Si te interesa (y por alguna razón sigues queriendo reinventar la rueda), ya nos lo dirás. Por otro lado, el caso particular de los exponentes enteros es una chorrada (tanto iterativa como recursivamente). Con lo cual no trato de decirte nada malo, sino que encontrarás muchos ejemplos, tanto en este foro como en cualquier otro sitio web. Además, ya que quieres que no haya bucles en tu programa, has de saber que es muy fácil y muy mecánico convertir una función iterativa (que seguramente ya sabes como se haría para este caso) en una recursiva. Un ejemplo con el factorial:

Código
  1. int factorial1(int n) { // Version iterativa
  2. int result = 1;
  3. for (int i = 2; i <= n; ++i) result *= i;
  4. return result;
  5. }
  6.  
  7. int factorial2(int n) { // Version recursiva
  8. if (n < 2) return 1;
  9. else return n*factorial2(n-1);
  10. }

Sólo tienes que aplicar lo mismo en tu caso (si sólo contemplas potencias enteras).

¡Saludos!


Título: Re: Codigo fuente de la funcion pow de math.h?
Publicado por: prometheus48 en 31 Enero 2012, 22:53 pm
GRacias chicos, si me interesa. No es un ejercicio de clase, porque como he dicho ya varias veces tengo 14 años.

¿Qué porque quiero hacerlo sin bucle?
Bueno, porque segun mi padre es AVSOLUTAMENTE IMPOSIBLE hacerlo sin bucle y sin funcion pow. ( mi padre no sabe programar pero sabe de lo que hablo porque de pequeño programó en BASIC ). Entonces es exactamente por eso.

El usuario que puso un comentario arriba, no me acuerdo el nombre lo siento, me interesa de lo que hablas...
¿POdrías explicar un poco?

Salu2!


Título: Re: Codigo fuente de la funcion pow de math.h?
Publicado por: Anastacio en 1 Febrero 2012, 13:42 pm
A, otro programador joven. Pues yo tengo 13, y me estoy liando con este post.

El codigo que se puso arriba, no serviria solo en caso de que los exponentes fuesen 0 o 1, y todos los demas???

Nota, no entendi el ultimo codigo, no puedo entender la sentencia for, me cuesta un Peru. Alguien me explica plisssss

Saludos!!!!


Título: Re: Codigo fuente de la funcion pow de math.h?
Publicado por: Ferno en 1 Febrero 2012, 14:47 pm
Nota, no entendi el ultimo codigo, no puedo entender la sentencia for, me cuesta un Peru. Alguien me explica plisssss

Saludos!!!!

Para entender ese tipo de códigos es mejor agarrar lápiz y papel y hacerse un cuadro de seguimiento del algoritmo con varios ejemplos, y uno se va dando cuenta. Sin embargo, al menos en el método iterativo, el código está mal.

Código
  1. for (int i = 1; i < n; ++i) result *= i; /*Si se mantiene el pre-incremente (incrementar antes de entrar al for), entonces i debe comenzar en 1, y la condición de corte debe ser menor estricto (sino entraría al for cuando i = 6 y no daría el resultado correcto*/

Código
  1. for (int = 2; i <= n; i++) result *= i; /*Sino debe incrementarse posterior a cada ciclco*/


Título: Re: Codigo fuente de la funcion pow de math.h?
Publicado por: ghastlyX en 1 Febrero 2012, 15:49 pm
Respecto a lo de elevar a exponentes reales, si soy sincero no me lo había planteado y no sé la mejor manera de hacerlo. Si tuviera que programarlo ahora lo haría en términos de la definición usando variable compleja de la potencia, que es términos de la exponencial y del logaritmo y que por tanto implican (sin usar esas dos funciones) series de Taylor. Pero si tienes 14 años, entrar en series de Taylor puede ser algo duro, necesitarías probablemente mucha base matemática de cosas que no conoces.

Respecto a lo que comenta Ferno, no sé por qué dices que está mal. Es lo mismo hacer
Código
  1. for (int i = 1; i < n; ++i)
que
Código
  1. for (int i = 1; i < n; i++)

El postincremento difiere del preincremento si se usa combinándolo con algo más, si no el resultado es equivalente. Como prueba simplemente hace falta considerar el siguiente código:
Código
  1. #include <iostream>
  2. using namespace std;
  3.  
  4. int factorial1(int n) { // Version iterativa
  5.    int result = 1;
  6.    for (int i = 2; i <= n; ++i) result *= i;
  7.    return result;
  8. }
  9.  
  10. int factorial2(int n) { // Version iterativa
  11.    int result = 1;
  12.    for (int i = 2; i <= n; i++) result *= i;
  13.    return result;
  14. }
  15.  
  16. int main() {
  17.    int n;
  18.    while (cin >> n) cout << factorial1(n) << " " << factorial2(n) << endl;
  19. }
Por ejemplo, la entrada
Código:
0
1
2
3
4
5
6
7
8

Produce la siguiente salida:
Código:
1 1
1 1
2 2
6 6
24 24
120 120
720 720
5040 5040
40320 40320


Título: Re: Codigo fuente de la funcion pow de math.h?
Publicado por: Ferno en 1 Febrero 2012, 15:54 pm
Lo dije porque estaba seguro de que el pre-incremento justamente incrementaba la variable antes de llamar a las funciones del bucle for.
Perdón entonces!


Título: Re: Codigo fuente de la funcion pow de math.h?
Publicado por: Xandrete en 1 Febrero 2012, 20:21 pm
GRacias chicos, si me interesa. No es un ejercicio de clase, porque como he dicho ya varias veces tengo 14 años.

¿Qué porque quiero hacerlo sin bucle?
Bueno, porque segun mi padre es AVSOLUTAMENTE IMPOSIBLE hacerlo sin bucle y sin funcion pow. ( mi padre no sabe programar pero sabe de lo que hablo porque de pequeño programó en BASIC ). Entonces es exactamente por eso.

El usuario que puso un comentario arriba, no me acuerdo el nombre lo siento, me interesa de lo que hablas...
¿POdrías explicar un poco?

Salu2!

Tampoco hacía falta recordar mi nombre... lo podías copiar y pegar, xD.

A ver, dile a tu padre que sí que se puede hacer sin bucle. Ejemplo;

Código
  1. #include <iostream>
  2. using namespace std;
  3.  
  4. int pow_aux(int b, int ex) {
  5. if (ex == 0) return 1;
  6. else return b*pow_aux(b,ex-1);
  7. }
  8.  
  9. double pow(int b, int ex) {
  10. if (ex > 0) return pow_rec(b,ex);
  11. else return 1.0/pow_rec(b,-ex);
  12. }
  13.  
  14. int main() {
  15. int a,b;
  16. cin >> a >> b;
  17. cout << pow(a,b) << endl;
  18. }

Y bueno, como te han comentado, hace falta tener base matemática para comprender como se haría en el caso del exponente real. Este es mi código:

Código
  1. #include <iostream>
  2. #include <cmath>
  3. #include <vector>
  4. #define GRADMACLAURINSERIES 20
  5. using namespace std;
  6.  
  7. vector<double> PolyExp;
  8.  
  9. vector<double> MacLaurinExp(int grad) {
  10. vector<double> Poly(grad+1);
  11. Poly[0] = 1;
  12. for (int i = 1; i <= grad; ++i)
  13. Poly[i] = Poly[i-1]/i;
  14. return Poly;
  15. }
  16.  
  17. double evalPoly(double x, vector<double> Poly) {
  18. double result = 0;
  19. for (int i = Poly.size()-1; i >= 0; --i)
  20. result = result*x + Poly[i];
  21. return result;
  22. }
  23.  
  24. double pow_aux(int ex) {
  25. if (ex == 0) return 1;
  26. else return M_E*pow_aux(ex-1);
  27. }
  28.  
  29. double pow(double b, double ex) {
  30. double result;
  31. ex *= log(b);
  32. if (ex > 0) result = pow_aux(int(ex));
  33. else result = 1.0/pow_aux(int(-ex));
  34. result *= evalPoly(ex-int(ex),PolyExp);
  35. return result;
  36. }
  37.  
  38. int main() {
  39. double x,y;
  40. PolyExp = MacLaurinExp(GRADMACLAURINSERIES);
  41. cin >> x >> y;
  42. cout.precision(10);
  43. cout << pow(x,y) << endl;
  44. }

MacLaurinExp devuelve los coeficientes de la serie de MacLaurin (polinomio de Taylor en x=0) de la función exponencial (ex) en un vector. polyEval evalúa el polinomio para un valor de x mediante el algoritmo de Horner.

En mi código, lo que hago básicamente es plantearme una potencia xy de la siguiente manera: eln(x)*y (sólo funciona para bases mayores que 0, claro, para bases menores que 0 el resultado es, en general, complejo, y se tendría que calcular de otra manera). ln(x)*y consta de parte decimal y parte entera. Pongamos que ln(x)*y = 5.64. Como e5.64=e5e0.64la serie de MacLaurin (polinomio de Taylor en x=0) de la función exponencial, lo que hago es evaluar e5 de la manera tradicional (mediante bucles o mediante una función recursiva, como en este caso con pow_aux) y e0.64 lo obtengo mediante el polinomio de Taylor de la función exponencial. Luego multiplico los dos resultados y listo, tengo xy. Insisto en que, para comprender esto, deberías saber lo que es el polinomio de Taylor de una función. Además, considerando que tu nivel de programación todavía no es muy alto, quizás deberías centrarte en seguir aprendiendo antes de preocuparte por estas cosas.

EDITO: Oh, y M_E es una macro definida en cmath, que contiene el número e con la máxima precisión que admite la máquina.

Saludos

EI: juntando mensajes.

Ah, aquí una implementación mucho más eficiente del algoritmo para exponentes enteros. Si bien en los algoritmos dados hasta ahora el coste era Θ(n), en éste el coste es Θ(log n), lo cual es una mejora MUY importante.

Código
  1. #include <iostream>
  2. using namespace std;
  3.  
  4. double pow_aux(double b, int e) {
  5. if (e == 0) return 1;
  6. else {
  7. double x = pow_aux(b, e/2);
  8. if (e%2) return x*x*b;
  9. else return x*x;
  10. }
  11. }
  12.  
  13. double pow(double b, int e) {
  14. if (e < 0) return 1/pow_aux(b,-e);
  15. else return pow_aux(b,e);
  16. }
  17.  
  18. int main() {
  19. double b;
  20. int e;
  21. cin >> b >> e;
  22. cout << pow(b,e) << endl;
  23. }