[C con Clase] Operaciones trigonométricas y C++

Santiago Tabarez santiago230792 en gmail.com
Mar Oct 9 00:41:28 CEST 2012


El 4 de octubre de 2012 02:59, Davidson, Steven <srd4121 en njit.edu> escribió:

> Hola Santiago,
>
> 2012/10/3 Santiago Tabarez <santiago230792 en gmail.com>:
> > Yo hace unos meses había empezado mi propio proyecto de una calculadora
> que
> > funcionara en línea de comandos (terminal).
> > En principio le había agregado las cuatro operaciones básicas, pero luego
> > les agregué otras, que son las funciones/macros contenidas en
> > el archivo cabecera cmath: pow, sqrt, sin, tan, cos, asin, atan, acos,
> log,
> > abs, asinh, acosh, atanh y algun otro más
> >
> > Pero como yo quería aprender un poco más de matemática y fortalecer mis
> > conocimientos de C++ puro con un ejemplo que me hiciera usar
> > muchas de sus posibilidades, decidí hacer mis propias funciones de las
> > operaciones. Esto es lo que hice en cuanto a las 4 operaciones básicas:
> >
>
> [CORTE]
>
> > ... e hice estas operaciones hasta el momento:
> >
> > double valor_absoluto (double x)
> > {
> >     if (x < 0) {
> >         return ((-x) * (2)) + (x);
> >     }
> >
> >     return x;
>
> El cálculo es demasiado complicado para algo tan sencillo como
> retornar: -x. Reescribiendo lo anterior, obtenemos,
>
> double valor_absoluto( double x )
> {
>   return x < 0.0 ? -x : x;
> }
>
>
Tu implementacion me gustóo y luce más limpia. Si no te importa la voy a
usar.


>  > }
> >
> > Quiero saber si estoy fallando en algo en esta operacion:
> >
> > double potenciacion (int base, int exp)
> > {
> >     int iResult;
> >
>
> Esto ya va a suponer un problema, porque vas a retornar este resultado
> cuando indicas que el valor de retorno es de tipo 'double'. El otro
> problema es que 'int' no tiene un intervalo muy grande para la
> potenciación. Sugiero que la base sea 'double', y así puedes crear una
> función más genérica. Si dejas el exponente como un entero, entonces
> puedes emplear un algoritmo optimizado para calcular la potenciación
> con una complejidad temporal de O(lg n), donde 'n' es el exponente.
>
> >     if ((base != 0) && (exp == 0))
> >         iResult = 1;
> >     else if ((base == 0) && (exp > 0))
> >         iResult = 0;
> >     else if (exp == 1)
> >         iResult = base;
>
> Esta última comprobación no es necesaria, ya que se puede tratar como
> el mismo caso general posterior.
>
> >     else {
> >         for (int iCounter = exp; exp > 1; iCounter--) (base * base);
>
> Esto no tiene mucho sentido. La sentencia, 'base * base', no es
> consecuente al finalizar el bucle, ya que hace un cálculo, pero ignora
> el resultado. Sospecho que querías hacer esto:
>
> iResult *= base;
>

Efectivamente quería hacer eso. Cuando escribí el email no presté mucha
antención y lo envié tal y como lo viste. Segundos despues de enviado,
revisé esta sentencia y me dí cuenta del error.


>
> Sin embargo, necesitas dar un valor inicial a 'iResult'. Esto sería,
>
> for( iResult = 1; exp > 0; exp-- )  iResult *= base;
>
> Como puedes ver, no necesitamos crear otra variable para controlar
> este bucle, ya que podemos usar 'exp' directamente. También puedes ver
> que combinamos el caso anterior cuando el exponente es 0 (cero).
>
> Sin embargo, existe otro método para calcular la potenciación que se
> basa en multiplicar cuadrados de la base. El bucle se basaría en
> recorrer la secuencia binaria del exponente, y por tanto realizamos
> menos iteraciones. Si te interesa este otro algoritmo, dímelo y te lo
> doy.
>

Claro, me gustaría saber cómo implementar este otro algoritmo. Hasta tal
vez podría resultar más eficiente.


>
> >     }
> >
> >     return iResult;
> > }
> >
>
> Además, sugiero agregar otra comprobación que es cuando el exponente
> es negativo, ya que indicaría la inversa del resultado que se acaba de
> calcular.
>

De esta otra comprobacion no me había dado cuenta, pero esto es lo que hice
para tratar de aplicarlo:

double potenciacion (double base, int exp)
    // potenciacion
{
    double dResult;

    if ((base != 0) && (exp == 0)) // cualquier número elevado a la 0
potencia da 1 como resultado
        dResult = 1;
    else if ((base == 0) && (exp > 0)) // si la base es cero y el exponente
distinto de cero, siempre dará como resultado cero
        dResult = 0;
    else if ((exp < 0) && (base != 0)) // si la base es distinta de cero y
el exponente negativo
        dResult = 1 / potenciacion (base, -exp);
    else {
        for (dResult = 1; exp > 0; exp--) // todos los demas casos
        {
            dResult *= base;
        }
    }

    return dResult;
}

Pero hay un caso que es cero elevado a la cero potencia ( 0º ) que en
principio sería indeterminado.


>
> > Así como está esta operacion, dependería de la anterior en que funcione
> > adecuadamente.
> >
> > double calc_root (double base, double root)
> > {
> >     return potenciacion (base, 1 / root);
>
> Esto no va a funcionar como esperas, aun teniendo la implementación
> correcta de la potenciación, ya que el exponente que pasas es de tipo
> 'double', mientras que 'potenciacion()' espera un entero. Además,
> matemáticamente puedes ver que tu implementación no realizará una
> iteración parcial para que los cálculos salgan bien. O sea, si el
> exponente es 1/2, para la raíz cuadrada, tu algoritmo no va a realizar
> media iteración dando el resultado que quieres.
>
> La solución es implementar un algoritmo numérico, como por ejemplo, la
> expansión de la serie de Taylor, con a=1, o el método de
> Newton-Raphson ( http://es.wikipedia.org/wiki/M%C3%A9todo_de_Newton ).
> Para terminar el método iterativo de Newton-Raphson, puedes comprobar
> un nivel de tolerancia entre el valor generado en la iteración actual
> y el valor de la iteración anterior.
>

Actualmente estoy intentando ver cómo implementar el método de
Newton-Raphson, que lo veo muy complicado. Por ahora voy a dejar las raíces
de lado un tiempo.


> > }
> >
> > En lo posible -a la amable persona que me asesore- si puede, que me de
> > pistas de lo que pueda estar fallando y de posibles errores en la
> > implementacion de C++.
> >
> > Tambien agradezco a Steven Davidson por contestar mi duda acerca de un
> > ejemplo de internet que modifique.
> >
>
> De nada; para esto estamos :)
>
>
> Espero que todo esto te oriente.
>
> Steven
>
> _______________________________________________
> Lista de correo Cconclase Cconclase en listas.conclase.net
> http://listas.conclase.net/mailman/listinfo/cconclase_listas.conclase.net
> Bajas: http://listas.conclase.net/index.php?gid=2&mnu=FAQ
>

Además creé una función que no esperaba crear, los factoriales. Utilicé
valores de tipo *long double *dada la posibilidad de que los resultados
puedan tomar valores muy grandes (el máximo valor al que devuelve un
resultado es 170, luego de eso devuelve un "*1.#INF*"). Si hay algo mal
avisame.

long double factorial (long double x)
    // cálculo de factoriales
{
    long double y = 1;

    while ( x > 1 ) {
        y *= x;
        x--;
    }
    return y;
}

Para finalizar quería agradecerle la asistencia y si puede por favor
explíqueme los algoritmos que me había propuesto.
------------ próxima parte ------------
Se ha borrado un adjunto en formato HTML...
URL: <http://listas.conclase.net/pipermail/cconclase_listas.conclase.net/attachments/20121008/311548cf/attachment.html>


Más información sobre la lista de distribución Cconclase