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

Davidson, Steven srd4121 en njit.edu
Jue Oct 4 07:59:06 CEST 2012


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;
}

> }
>
> 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;

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.

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

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

> }
>
> 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




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