Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: norris en 5 Noviembre 2012, 14:14 pm



Título: Logaritmo sin librería Math.t
Publicado por: norris en 5 Noviembre 2012, 14:14 pm
Hola, muy buenas. El código para hallar Logaritmo(base n) de un numero m es el siguiente. Ahora me piden un código para hallar lo mismo pero sin usar la librería math.h

Código:
#include <stdio.h>
#include <math.h>

float logaritmo(double argumento, double base){
return log10(argumento)/log10(base);
}

int main() {
double n, base, resultado;
printf ("Ingrese número: ");
scanf("%lf", &n);
printf ("Ingrese base: ");
scanf("%lf", &base);
resultado = logaritmo (n, base);
printf ("Resultado: %f", resultado);
return 0;
}

Gracias de antemano


Título: Re: Logaritmo sin librería Math.t
Publicado por: claudioxis en 31 Marzo 2013, 23:20 pm
tengo la misma duda, si alguien llego a la solución por favor me explica de ante mano gracias


Título: Re: Logaritmo sin librería Math.t
Publicado por: claudioxis en 31 Marzo 2013, 23:39 pm
haber voy hacer otra pregunta amigo se puede hacer el logaritmo de x en base 2 sin la librería math y si se puede como se hace?


Título: Re: Logaritmo sin librería Math.t
Publicado por: diskontrol en 1 Abril 2013, 00:46 am
Un método sencillo es el de dividir y elevar (aunque seguro que tiene otro nombre :-D).

Coges el número y lo divides por la base hasta que sea menor que ésta. El número de divisiones es la parte entera del logaritmo. Después coges el resultado de la última división y lo elevas a la base, vuelves a dividir hasta que sea menor y obtienes el primer decimal. Repites hasta que tengas los decimales que quieras.

Saludos.


Título: Re: Logaritmo sin librería Math.t
Publicado por: durasno en 1 Abril 2013, 03:03 am
Hola! creo q diskontrol se refiere a: http://www.youtube.com/watch?v=AqeLDG7XM8g

Igual me parece que no es tan facil de esa manera. SIno creo q tambien se puede usando series(pero aca necesitas un poco mas de conocimiento matematico).. EN fin fijate si podes hacerlo de alguna manera


Saludos

PD: busca si hay otros metodos mas sencillos para poder programar


Título: Re: Logaritmo sin librería Math.t
Publicado por: diskontrol en 1 Abril 2013, 12:29 pm
...Igual me parece que no es tan facil de esa manera...

Si hacer un bucle con una comparación que haga divisiones y una potencia te parece difícil....


Título: Re: Logaritmo sin librería Math.t
Publicado por: MeCraniDOS en 1 Abril 2013, 13:40 pm
(Solución Tonta) Abres math.h con el bloc de notas, te copias la función del logaritmo y la pones en tu programa, listo, ya no tienes que llamarla...  :silbar: :silbar:

Saludos


Título: Re: Logaritmo sin librería Math.t
Publicado por: rir3760 en 1 Abril 2013, 14:56 pm
(Solución Tonta) Abres math.h con el bloc de notas, te copias la función del logaritmo y la pones en tu programa, listo, ya no tienes que llamarla
El encabezado <math.h> solo contiene el prototipo de la función.

Un saludo


Título: Re: Logaritmo sin librería Math.t
Publicado por: NeoB en 1 Abril 2013, 16:06 pm
Solo hay que buscar un poco en google:
http://www.raspberryginger.com/jbailey/minix/html/lib_2math_2log_8c-source.html (http://www.raspberryginger.com/jbailey/minix/html/lib_2math_2log_8c-source.html)
He de decir que no lo he aprobado, pero si puedo contribuir, ahí va.


Título: Re: Logaritmo sin librería Math.t
Publicado por: durasno en 1 Abril 2013, 20:06 pm
Citar
Si hacer un bucle con una comparación que haga divisiones y una potencia te parece difícil....
ok ok entonces no le va a costar mucho hacerlo, mejor para norris.. de todas formas contamos con toda tu experiencia  :)


Título: Re: Logaritmo sin librería Math.t
Publicado por: do-while en 2 Abril 2013, 11:43 am
¡Buenas!

Creo que lo mas intuitivo es trabajar con la funcion inversa y aplicar Bolzano (http://es.wikipedia.org/wiki/Teorema_del_valor_intermedio):

x = loga(b) -> ax = b -> ax - b = 0

Por lo tanto se trata de encontrar el cero de la función f(x) = ax - b

Aplicando un poco de analisis sabemos que ax es siempre positivo (siempre que a sea positivo), por lo tanto tal cero existirá si y solo si b es positivo.

En estas condiciones tendrás que buscar dos puntos x0 y0 en los que la función tenga signo distinto. Así sabrás que el cero de la función se encuentra entre estos dos puntos.

Solo te queda iterar. En cada paso tendrás que buscar el punto medio del intervalo y evaluarlo para saber si la función toma un valor positivo o negativo en dicho punto. Una vez sepas el valor de la función al evaluarlo en el punto medio podrás sustituir la cota superior o inferior que tenias inicialmente por el punto medio.

Este proceso parará cuando:
- La evaluación de la función en el punto medio de exactamente cero.
- La diferencia entre la cota superior e inferior sea menor a un valor que tu consideres un error aceptable para la solución del problema.
- Cuando entre una iteración y la siguiente no cambie el punto medio (esto sucede debido al incremento mínimo que existe en la representación interna de números en coma flotante)

El valor que devolverá la función logaritmo será el punto medio del intervalo en el que han acabado las iteraciones, ya que será el valor de x que ha hecho que la función f(x) = ax - b se aproxime mas a cero (el valor mas proximo a loga(b))

¡Saludos!


Título: Re: Logaritmo sin librería Math.t
Publicado por: Puntoinfinito en 2 Abril 2013, 17:54 pm
Hey! Tienes dos opciones, o copiar la función de log() directamente desde la librería math.h  :xD

Ó hacerlo de la siguiente manera;

Debes aplicar un algoritmo matemático y hacerlo de manera estándar.

(http://upload.wikimedia.org/math/a/0/b/a0b4ff44d6aa2ee6e54dc6dab9674909.png)

Por lo tanto

(http://upload.wikimedia.org/math/0/3/0/03043798d28801e158afea021afe1266.png)

Como ves se ha de pasar de un calculo logarítmico hacía uno exponencial.

Código:
log 10 (a) = ? ; 10[sup]x[/sup] = a

La x esta porque no sabemos el resultado de ese logaritmo, en caso de que lo tuviéramos sería tal como el ejemplo de la imagen anterior. Como no es así, elevamos una incógnita y factorizamos  a
. Imaginemos que a nos ha dado 5. Entonces, ahora tenemos 10x = 10[ sup]5[/sup]. Comparamos antes de factorizar y después de hacerlo y vemos que las bases son las mismas, entonces al ser las mismas las ignoramos y el número que nos ha la factorización es el resultante. x = 5

PD: Creo que era así


Título: Re: Logaritmo sin librería Math.t
Publicado por: avesudra en 3 Abril 2013, 00:01 am
Implementando de manera rápida lo que comentó @diskontrol que como he podido comprobar solo es válido para logaritmos en base 10, he sacado este código (seguro que es un churro, no me mateis   :( ). En cuanto lo último comentado por @Puntoinfinito eso solo vale para logaritmos exactos. ¿@do-while al fin y al cabo es ensayo y error no? Si yo tengo log24 -> 2x = 4 vas probando valores enteros hasta que tengas un resultado mayor que 4 o igual y vas reduciendo ... no sé tampoco tengo nivel matemático para hacerlo, implemente la serie de Taylor pero es muy lenta, dejo el código al que @diskontrol se refería:
Código
  1. #include <iostream>
  2. #include <sstream>
  3. #include <string>
  4.  
  5. using namespace std;
  6.  
  7. #define PRECISION 1000
  8.  
  9. #define e 2.7182818284590452353602874713526624977572470936999595749669676277240766303535
  10.  
  11. double ln (double num);
  12. double log10 (double num, std::string &str);
  13. double pow (double base, register int exp);
  14.  
  15.  
  16. int main(int argc , char * argv [])
  17. {
  18.    string str;
  19.    cout <<"Resultado en la precision maxima de de double es: "<< log10(34.4,str) << endl;
  20.    cout << "Resultado truncado a "<< PRECISION << " decimales es: " << endl<< str;
  21.    return 0;
  22. }
  23.  
  24. double pow (double base, register int exp)
  25. {
  26.    double ret = 1;
  27.    while(exp!=0)
  28.    {
  29.        ret = base*ret;
  30.        --exp;
  31.    }
  32.    return ret;
  33. }
  34. double ln (double num)
  35. {
  36.    string unused;
  37.    return (log10(num,unused)/log10(e,unused));
  38. }
  39. double log10 (double num,std::string &str)
  40. {
  41.    double ret = 0;
  42.    double decimal  = 0;
  43.  
  44.    if(num < 10)
  45.        num = pow(num,10);
  46.    else
  47.    {
  48.        while(num >= 10)
  49.        {
  50.            num /= 10;
  51.            ++ret;
  52.        }
  53.        num = pow(num,10);
  54.    }
  55.  
  56.    ostringstream convert;   // stream usado para la conversión.
  57.    convert <<ret;
  58.    str += convert.str();
  59.    str += '.';
  60.    for(register int i = 1 ; i != PRECISION; ++i)
  61.    {
  62.        while(num >= 10)
  63.        {
  64.            num /= 10;
  65.            ++decimal;
  66.        }
  67.        ret += decimal*(1/(pow(10,i)));
  68.        num = pow(num,10);
  69.  
  70.        str +=(char) decimal+48;
  71.        decimal = 0;
  72.    }
  73.    return ret;
  74. }


Título: Re: Logaritmo sin librería Math.t
Publicado por: diskontrol en 3 Abril 2013, 03:08 am
...IImplementando de manera rápida lo que comentó @diskontrol que como he podido comprobar solo es válido para logaritmos en base 10...
Puedes usarlo para cualquier base. No está en c, que así es más rápido, pero se entiende facil

Código
  1. function[x]=loga(num,basenum,baselog,decimales)
  2.    x=0;
  3.    for i=0:decimales
  4.        contador=0;
  5.        while num > baselog then
  6.            num=num/baselog;
  7.            contador=contador+1;
  8.        end
  9.        num=num^basenum
  10.        x=x+(contador/(10^i))
  11.    end
  12. endfunction

Código
  1. -->loga(12345,10,%e,4)
  2. ans  =
  3.  
  4.    9.421  
  5.  
  6. -->log(12345)
  7. ans  =
  8.  
  9.    9.4210064

Hay que usarlo con cuidado porque tiene limitaciones y no tiene en cuenta ni si quiera el dominio del logaritmo :-P


Título: Re: Logaritmo sin librería Math.t
Publicado por: do-while en 3 Abril 2013, 11:13 am
¿@do-while al fin y al cabo es ensayo y error no?

XD, si y no. Se puede considerar una especie de ensayo y error, pero aplicando la lógica. Después del primer paso conseguimos dos puntos x0, y0 en los que la función evaluada en el primero punto, en este caso en concreto, es menor que cero y evaluada en el segundo es mayor que cero:

                                                                      f(y0)



x0------------------------------------------------------y0 (eje OX)


f(x0)

Como la función es continua, si unes f(x0) y f(y0) con una linea, siempre tendrás que atravesar el eje OX. Es decir, en algún punto entre x0 e y0 la función sera cero. Ese es el punto que buscamos y sabemos que está entre ambos valores.

Por lo tanto obtenemos el punto z0 = (x0 + y0) / 2 y evaluamos la función en dicho punto. Imagina que sale que la función es positiva en z0:

                                                                      f(y0)

                                    f(z0)

x0---------------------------z0--------------------------y0 (eje OX)


f(x0)

Sigue sucediendo lo mismo de antes, entre x0 y z0 la función se anula, pero ahora tenemos un intervalo mas pequeño que el primero. Como z0 da un valor positivo, hacemos x1 := x0 e y1 := z0. Y aplicamos el proceso anterior al intervalo [x1,y1] para obtener un punto z1 que estará todavía mas próximo al cero de la función.

A fin de cuentas se trata de eso. De aproximar en cada paso cada vez mas el cero de la función dividiendo el intervalo de búsqueda en cada iteración. Si consideramos un error e, se tendrá que:

(y0 - x0) / 2n < e si y solo si

y0 - x0 < e 2n si y solo si

(y0 - x0) / e < 2n si y solo si

log2((y0 - x0) / e) < n

Es decir, como mucho tendremos que iterar una vez mas que la parte entera de log2((y0 - x0) / e) para obtener un resultado que se aproxime a la raíz con una precisión mayor que e/2.

¡Saludos!