[Ayuda] Codificar función matemática en C++

Pues bien, estoy estudiando Telecomunicaciones en la EPSIG (Gijón) y tengo un ejercicio que no consigo resolver. Antes de que dejéis de leer y me digás que siga intentándolo, que aprenda por mi mismo, etc... no quiero el código en si, sólo que me ayudéis con la declaración de las variables, que en una función no lo acabo de entender.

Este es el ejercicio, por si lo queréis ver:

sesion8.pdf (110.58 KB)

Ejercicio en PDF

Esta es la funcion principal.
V(h, r, L)= L*[0.5*pi*(r^2)-(r^2)*arcsin(h/r)-h*(((r^2)-(h^2))^1/2)]

Luego expone la Régula Falsi mediante la cual haya las raíces. Hay más información en el PDF.

EDIT: Gracias por la ayuda. Llegados a este punto, creo que mi problema es puramente matemático. Me compila bien, pero no consigo que salga lo que me piden. [mamaaaaa]

Código actualizado:
/*
  Nombre: Prácticas de Tablero 3.2
  Nick: lamateporunyogur
  Fecha: 25/10/09 20:37
  Descripcion: Aplicación de la práctica 3.2 de Elementos de Programación.
 
  Problema: Por más que lo intento, el resultado es una indeterminación.
  No consigo reducir el valor de h hasta uno menor a 10^(-3).
  O me da indeterminación, o me da 0. Espero que pueda exponer la solución.
*/

#include <iostream>
#include <cmath>

using namespace std;

main(void) {
       float pi=3.14159, h;
       double V, error, max, f, r, a, b;
       double Ra, Rb; //Resultados f(a) y f(b)
       int L;
       f=(L*(0.5*pi*pow(r,2)-pow(r,2)*asin(h/r)-h*(sqrt((r*r)-(h*h)))))-V;//Declaramos la funcion despejando V.
       r=1;
       L=10;
       V=12,4;
       error=1;
       max=0.001;
       a=0;//h debe ser menor que el radio, y por ello está entre 0 y 1.
       b=1;
       Ra=0;
       Rb=0;
       
       
       while(error>max){
                         //Función principal
                         h = (a-(Ra*(b-a)/Rb-Ra));
   
                         //Actualizamos error
                         error = (fabs((h-V)*(h-V)));
   
                         //Calculamos resultados
                         Ra = (L*(0.5*pi*pow(r,2)-pow(r,2)*asin(a/r)-h*(sqrt((r*r)-(a*a)))))-V;
                         Rb = (L*(0.5*pi*pow(r,2)-pow(r,2)*asin(b/r)-h*(sqrt((r*r)-(b*b)))))-V;
                         
                         //Actualizamos intervalos
                         if((Ra*f) < 0)
                           b = h;
                         else
                           a = h;
                           
                           }
       cout << "Practica 3.2 - Elementos de Programacion\n\n" <<"Solucion= " << h << "\n\n";
       system ("pause");
       return(0);
       }
       


Si alguien se anima a ver el problema y ayudarme bien, sino, nada. El código está bien en sí, pero no me sale el valor pedido.
Saludos [ginyo]
Voy a intentar ayudarte, aunque a lo mejor lo que te digo ya lo sabes XD.

Te piden la altura, con lo que tienes un rango a0 - b0 en el cual la respuesta debera estar incluida. Asi que, yo inicializaria unas variables a=0 y b = 100 por ejemplo (considerando que la altura este entre esos dos valores, pero es que no veo que lo ponga por ninguna parte).

Despues definiria la funcion del volumen, pero de otra forma. Sustituye los datos que te dan y pasa la V restando al otro lado (sabes que vale 1 si pones el valor de altura correcto, con lo que ahora si todo esta correcto sera igual a cero). Es decir, tienes una funcion que recibe solo como parametro h y dara cero cuanto mas te acerques a la solucion.

Aqui empezaria un bucle en el que evaluarias una h igual a la formula que te dan en el pdf para xn+1 partiendo de los valores iniciales de a y b. Haces el cuadrado de lo que te de la funcion evaluada en ese h y tendras el error. Ahi compruebas si es menor que 10e-3 y decides si actualizas los valores de a y b o si ya has dado con la solucion.


Creo que seria asi mas o menos y con C++ no puedo ayudarte porque yo no lo he estudiado (estos ejercicios los hacemos aqui con Matlab...).

Suerte y un saludo!
Yo tuve que hacer hace unos años el método de la regula falsi en C, a ver si te sirve

//Asignatura: Ampliacion de Matematicas
//Practica 1, ejercicio 2b
//Metodo de la Regula Falsi, Apartado B

#include <stdio.h>
#include <math.h>


int
main(void)
{
  double tol = 0.0000001;  //Tolerancia del error
  double x;  //Almacena el punto medio del intervalo a,b
  double a,b; //Intervalos
  double aR,bR,xR; //Resultados
  double error = 1; //Se pone a 1 para que entre por primera vez en el while
  int i = 0;  //Contador
 
  a = 2;  //Definimos limite inferior intervalo
  b = 3;  //Definimos limite superior intervalo
 
  while(error > tol){
    //Actualizamos contador
    i++;
   
    //Calculamos punto medio
    x = (((-aR)*(b-a)/(bR-aR))+a);
   
    //Actualizamos error
    error = (fabs(x - 2.41679918));
   
    //Calculamos resultados
    aR = (pow(a,4)-pow(a,3)-20);
    bR = (pow(b,4)-pow(b,3)-20);
    xR = (pow(x,4)-pow(x,3)-20);
   
   
    //Actualizamos intervalos
    if((aR*xR) < 0)
      b = x;
    else
      a = x;
     
    //Mostramos resultados por pantalla
    printf("x: %.15f\nerror: %.15f\niteracion %d\n\n",x,error,i);
  }   
         
  getchar();
}


La función a la cual hallar las soluciones está debajo del comentario "calculamos resultados"

Eso sí, intenta entenderlo y no copiarlo y si quieres pon tu solución en el post cuando la hagas.
Muchas gracias por colaborar, pero no me termina de salir. Esto es lo que llevo.

/*
  Name: Prácticas de Tablero 3.2
  Copyright:
  Author: lamateporunyogur
  Date: 27/10/09 20:37
  Description:
*/

#include <iostream>
#include <cmath>
using namespace std;

main(void) {
       float pi=3.14159, h, a, b;
       double V, error, max, f;
       double Ra, Rb, Rh; //Resultados falsi
       int L, r;
       f=(L*(0.5*pi*(r^2)-(r^2)*asin(h/r)-h*(sqrt((r*r)-(h*h)))))-V;//Declaramos la funcion despejando V.
       r=1;
       L=10;
       V=12,4;
       error=1;
       max=0.001;
       a=0;//h debe ser menor que el radio, y por ello está entre 0 y 1.
       b=1;
       
       while(error>max){
                         //Función principal
                         h = (a-(Ra*(b-a)/Rb-Ra));
   
                         //Actualizamos error
                         error = (fabs((h-V)*(h-V)));
   
                         //Calculamos resultados
                         Ra = (L*(0.5*pi*(r^2)-(r^2)*asin(a/r)-h*(sqrt((r*r)-(a*a)))))-V;
                         Rb = (L*(0.5*pi*(r^2)-(r^2)*asin(b/r)-h*(sqrt((r*r)-(b*b)))))-V;
                         
                         //Actualizamos intervalos
                         if((Ra*f) < 0)
                           a = h;
                         else
                           b = h;
                           
                           }
       cout << "h= " << h << "\n";
       system ("pause");
       return(0);
       }


Me da como resultado h=1.#IND
No consigo aproximar el valor de h a 0 llegando a 10^-3

A ver si podéis hacer algo. [ginyo]
Yo te ayudaría pero aún estoy con Pascal xD
^ no sirve para elevar, si no que es un XOR, que no tiene nada que ver.

Para elevar debes usar pow().
GameZelda escribió:^ no sirve para elevar, si no que es un XOR, que no tiene nada que ver.

Para elevar debes usar pow().


Efectivamente, para elevar se usa pow(). Anda que no me equivocaba yo veces con eso [tomaaa]

Así a voz de pronto no veo más cosas, en principio está bien.
Si pongo pow, me da error al compilar.
23 C:\Documents and Settings\lamateporunyogur\Escritorio\Practica 3.2.cpp call of overloaded `pow(int&, int)' is ambiguous

Y como ese muchos más.

Código actualizado:
/*
  Nombre: Prácticas de Tablero 3.2
  Nick: lamateporunyogur
  Fecha: 25/10/09 20:37
  Descripcion: Aplicación de la práctica 3.2 de Elementos de Programación.
 
  Problema: Por más que lo intento, el resultado es una indeterminación.
  No consigo reducir el valor de h hasta uno menor a 10^(-3).
  O me da indeterminación, o me da 0. Espero que pueda exponer la solución.
*/

#include <iostream>
#include <cmath>
#include <math.h>
using namespace std;

main(void) {
       float pi=3.14159, h, a, b;
       double V, error, max, f;
       double Ra, Rb, Rh; //Resultados f(a) y f(b)
       int L, r;
       f=(L*(0.5*pi*pow(r,2)-pow(r,2)*asin(h/r)-h*(sqrt((r*r)-(h*h)))))-V;//Declaramos la funcion despejando V.
       r=1;
       L=10;
       V=12,4;
       error=1;
       max=0.001;
       a=0;//h debe ser menor que el radio, y por ello está entre 0 y 1.
       b=1;
       
       while(error>max){
                         //Función principal
                         h = (a-(Ra*(b-a)/Rb-Ra));
   
                         //Actualizamos error
                         error = (fabs((h-V)*(h-V)));
   
                         //Calculamos resultados
                         Ra = (L*(0.5*pi*pow(r,2)-pow(r,2)*asin(a/r)-h*(sqrt((r*r)-(a*a)))))-V;
                         Rb = (L*(0.5*pi*pow(r,2)-pow(r,2)*asin(b/r)-h*(sqrt((r*r)-(b*b)))))-V;
                         
                         //Actualizamos intervalos
                         if((Ra*f) < 0)
                           b = h;
                         else
                           a = h;
                           
                           }
       cout << "Practica 3.2 - Elementos de Programacion\n\n" <<"Solucion= " << h << "\n\n";
       system ("pause");
       return(0);
       }
       
(mensaje borrado)
Si miras el error con mas detenimiento, verás que pow necesita que el primer argumento sea un double/long double/float, así que o declaras tu variable r como double o le haces un casting poniendo (double)r cada vez que la vayas a usar en la función pow.

Por otro lado la biblioteca cmath es lo mismo que math.h, por lo que puedes quitar la última del include.

Y para terminar, si usas variables sin inicializar te puede salir cualquier cosa, fijate que lo unico que has inicializado es pi y luego calculas f a partir de valores no inicializados.
<p>
Korso10 escribió:<br>Y para terminar, si usas variables sin inicializar te puede salir cualquier cosa, fijate que lo unico que has inicializado es pi y luego calculas f a partir de valores no inicializados.
IMPORTANTISIMO ESTO. Estás usando variables locales, estas viven en la pila (stack) y por tanto si no les pones valor tendrán un valor basura (de lo que hubiera antes en la pila). En C (y seguramente C++) sólo se hace la inicialización de variables automática si éstas son globales.
Vale
Korso10 escribió:Si miras el error con mas detenimiento, verás que pow necesita que el primer argumento sea un double/long double/float, así que o declaras tu variable r como double o le haces un casting poniendo (double)r cada vez que la vayas a usar en la función pow.

Por otro lado la biblioteca cmath es lo mismo que math.h, por lo que puedes quitar la última del include.

Y para terminar, si usas variables sin inicializar te puede salir cualquier cosa, fijate que lo unico que has inicializado es pi y luego calculas f a partir de valores no inicializados.
juas escribió:<p>
Korso10 escribió:<br>Y para terminar, si usas variables sin inicializar te puede salir cualquier cosa, fijate que lo unico que has inicializado es pi y luego calculas f a partir de valores no inicializados.
IMPORTANTISIMO ESTO. Estás usando variables locales, estas viven en la pila (stack) y por tanto si no les pones valor tendrán un valor basura (de lo que hubiera antes en la pila). En C (y seguramente C++) sólo se hace la inicialización de variables automática si éstas son globales.

Gracias por la ayuda. Llegados a este punto, creo que mi problema es puramente matemático. Me compila bien, pero no consigo que salga lo que me piden. [mamaaaaa]

Código actualizado:
/*
  Nombre: Prácticas de Tablero 3.2
  Nick: lamateporunyogur
  Fecha: 25/10/09 20:37
  Descripcion: Aplicación de la práctica 3.2 de Elementos de Programación.
 
  Problema: Por más que lo intento, el resultado es una indeterminación.
  No consigo reducir el valor de h hasta uno menor a 10^(-3).
  O me da indeterminación, o me da 0. Espero que pueda exponer la solución.
*/

#include <iostream>
#include <cmath>

using namespace std;

main(void) {
       float pi=3.14159, h;
       double V, error, max, f, r, a, b;
       double Ra, Rb; //Resultados f(a) y f(b)
       int L;
       f=(L*(0.5*pi*pow(r,2)-pow(r,2)*asin(h/r)-h*(sqrt((r*r)-(h*h)))))-V;//Declaramos la funcion despejando V.
       r=1;
       L=10;
       V=12,4;
       error=1;
       max=0.001;
       a=0;//h debe ser menor que el radio, y por ello está entre 0 y 1.
       b=1;
       Ra=0;
       Rb=0;
       
       
       while(error>max){
                         //Función principal
                         h = (a-(Ra*(b-a)/Rb-Ra));
   
                         //Actualizamos error
                         error = (fabs((h-V)*(h-V)));
   
                         //Calculamos resultados
                         Ra = (L*(0.5*pi*pow(r,2)-pow(r,2)*asin(a/r)-h*(sqrt((r*r)-(a*a)))))-V;
                         Rb = (L*(0.5*pi*pow(r,2)-pow(r,2)*asin(b/r)-h*(sqrt((r*r)-(b*b)))))-V;
                         
                         //Actualizamos intervalos
                         if((Ra*f) < 0)
                           b = h;
                         else
                           a = h;
                           
                           }
       cout << "Practica 3.2 - Elementos de Programacion\n\n" <<"Solucion= " << h << "\n\n";
       system ("pause");
       return(0);
       }
       


Si alguien se anima a ver el problema y ayudarme bien, sino, nada. El código está bien en sí, pero no me sale el valor pedido.
Saludos [ginyo]
Una cosilla y no sé si es que está así en el código o te has equivocado al copiárnoslo. Pero pones V = 12,4 cuando un número en coma flotante en C y C++ se separa la parte entera de la decimal por un punto en lugar de una coma (de hecho en el resto del programa tienes puesto puntos, por eso digo que lo mismo es un error al copiárnoslo).

Luego, la variable "f", pones ese tochazo bueno, jeje, pero al final del todo le restas V, pero V aparece inicializada después. Bueno y ahora que me fijo mejor, en "f" utilizas variables que son inicializadas más tarde. Creo que el problema está ahi, en que tienes que reorganizar el código. Primero pon las variables inicializadas (V=12.4, r=1,L=10, etc.) y luego pon el valor de f (f = tochazo xD).

Y creo, así por encima, que el bucle está bien.

Lo de inicializar las variables, tengo entendido que C++ por defecto inicializa a 0 las variables, pero siempre es más seguro inicializarlas.

Ya nos cuentas, ;)

saludos!!

EDITO: Como consejo personal, cuando tienes cosas como la asignación de f así de larga, lo ideal es que te crearas una función para tener más organizado y visible el código.

No sé como se llama el cálculo que haces en f, pero si se llama Calculo_X, pues create una función "Calculo_X(...)" con los parámetros que necesites ("Calculo_X(L, V, etc)"). Así, en lugar de tener que copiar y pegar ese tocho en el resto del código, como por ejemplo tienes en el bucle while que está repetido 2 veces más, pues llamas a dicha función creada pasándole los respectivos parámetros. Además, así es más fácil localizar el error, ya que si tienes 3 veces el tocho, puede que en 1 o 2 de ellas estén mal, o incluso las 3, y tienes que corregirlas una a una, mientras que llamando a la función, si está mal, está mal en las 3 y solo tienes que corregir la función.
Iba a decir lo mismo que ercea, usas un montón de variables que no inicializas, y que en el mejor de los casos contendrán 0, y en el peor, basura aleatoria. La parte matemática no la he mirado.
Primero, unas correcciones "simples":

La función system() esta definida en cstdlib:

#include <cstdlib>


main() debe retornar siempre un int:

int main(void) {


Se debe usar un punto y no una coma, que es un operador diferente (y no sé lo que hace exactamente [+risas] )

       V=12.4;


Luego el resto de errores ya están en el cálculo, creo:

f=(L*(0.5*pi*pow(r,2)-pow(r,2)*asin(h/r)-h*(sqrt((r*r)-(h*h)))))-V;//Declaramos la funcion despejando V.


No has definido ni "L", ni "r", ni "h", ni "V", con lo cual el resultado es indefinido (lo más probable es que sea NaN).

h = (a-(Ra*(b-a)/Rb-Ra));


En la primera iteración del bucle, hay una división entre cero (si no me equivoco) y esto hace que h sea NaN.

Con esto, todas las operaciones con NaN resultan en NaN, por lo que el resto del codigo sale todo NaN, y el bucle también se acaba porque "error" es NaN y la comparación de NaN con cualquier valor es falsa.

EDITO: He mirado el enunciado y he visto otro error (creo):

[code]h = (a-(Ra*(b-a)/Rb-Ra));


Rb-Ra deberia estar en un paréntesis (creo).
Aparte, que es f()? Creo que en el codigo lo has puesto como fabs(), que es el valor absoluto...
Eso me pregunto yo, la verdad que no lo recuerdo todo pero el compilador no chilla si te equivocas de poner coma en lugar de punto? Qué interpreta? Lo probaría ahora mismo pero me da flojera a estas horas xD.

saludos!
ercea escribió:Eso me pregunto yo, la verdad que no lo recuerdo todo pero el compilador no chilla si te equivocas de poner coma en lugar de punto? Qué interpreta? Lo probaría ahora mismo pero me da flojera a estas horas xD.

saludos!


EDITO: http://www.zator.com/Cpp/E4_9_5.htm (el link que habia antes era de JScript [+risas] pero creo que funciona igual).

En mi caso (GCC sobre Linux) el compilador dice:

warning: right-hand operand of comma has no effect


Pero el código compila porque es legal.
Jeje, si bueno, quería decir eso, o un error, o al menos un warning, me imaginaba que o bien se quedaba con el primer valor o bien con el último xD.

Gracias por contestar ;)

saludos!
Respecto a eso, un consejo: activa siempre todos los warnings del compilador, y hazles caso. Suelen tener razón :P
Con GCC se activan con -Wall si mal no recuerdo.
Que active mejor el modo pedante [qmparto] , tenia en la universidad un tutor que, al entregar ciertas prácticas de problemas de c++, ejecutaba un script que recorría carpeta por carpeta, ejercicio por ejercicio, compilando los problemas en modo pedantic y lo utilizaba como criterio de apto no apto dependiendo del número de errores xD( cosas enplan "en el for has puesto un int en lugar de un unsigned int" xD, eso sí, uno aprende mejor de estas cosas por supuesto xD).

saludos!
melado escribió:Respecto a eso, un consejo: activa siempre todos los warnings del compilador, y hazles caso. Suelen tener razón :P
Con GCC se activan con -Wall si mal no recuerdo.


A nosotros en clase los warning nos los tratan como errores, así que programa con warnings = suspenso [+risas] .
Ciertos warning pueden ser cagadas muy grandes, como ha dicho melado es mejor hacerles caso [risita] .
Tras intentarlo todo, no consigo que me salga nada más que indeterminación.
En cuanto al consejo de crear la funcion...

ercea escribió:[...]
Como consejo personal, cuando tienes cosas como la asignación de f así de larga, lo ideal es que te crearas una función para tener más organizado y visible el código.

No sé como se llama el cálculo que haces en f, pero si se llama Calculo_X, pues create una función "Calculo_X(...)" con los parámetros que necesites ("Calculo_X(L, V, etc)"). Así, en lugar de tener que copiar y pegar ese tocho en el resto del código, como por ejemplo tienes en el bucle while que está repetido 2 veces más, pues llamas a dicha función creada pasándole los respectivos parámetros. Además, así es más fácil localizar el error, ya que si tienes 3 veces el tocho, puede que en 1 o 2 de ellas estén mal, o incluso las 3, y tienes que corregirlas una a una, mientras que llamando a la función, si está mal, está mal en las 3 y solo tienes que corregir la función.

¡No sé hacer eso!
Y no hay manera de encontrar nada en internet que me lo explique.
Si me pudierais esquematizar el proceso... como hay que definirla, como deben definirse las variables, etc.

Saludos [ginyo]
Antes de nada, ¿has arreglado el tema de las variables sin inicializar? Porque eso es impepinable, o lo arreglas, o no va a funcionar.

Edit: aparte, en el primer cálculo de f, haces un:
asin(h/r)


De ahí sale el NaN, porque r (de casualidad) es 0, y las divisiones por cero son peligrosas [carcajad]
Si, ya declarlo las variables y las inicializo. r es 1 siempre, así que no puede haber ningún conflicto.
Aun así, me sigue dando 1.#IND como resultado.

Código actualizado:
/*
  Nombre: Prácticas de Tablero 3.2
  Nick: lamateporunyogur
  Fecha: 25/10/09 20:37
  Descripcion: Aplicación de la práctica 3.2 de Elementos de Programación.
 
  Problema: Por más que lo intento, el resultado es una indeterminación.
  No consigo reducir el valor de h hasta uno menor a 10^(-3).
  O me da indeterminación, o me da 0. Espero que pueda exponer la solución.
*/

#include <iostream>
#include <cmath>
#include <cstdlib>

using namespace std;

int main(void) {
       float pi=3.14159, h;
       double V, error, max, f, r, a, b;
       double Ra, Rb; //Resultados f(a) y f(b)
       int L;
       r=1;
       L=10;
       V=12.4;
       h=0;
       error=1;
       max=0.001;
       a=0;//h debe ser menor que el radio, y por ello está entre 0 y 1.
       b=1;
       Ra=0;
       Rb=0;
       f=(L*(0.5*pi*pow(r,2)-pow(r,2)*asin(h/r)-h*(sqrt((r*r)-(h*h)))))-V;//Declaramos la funcion despejando V.
       
       
       while(error>max){
                         //Función principal
                         h = (a-(Ra*(b-a)/(Rb-Ra)));
   
                         //Actualizamos error
                         error = (fabs((h-V)*(h-V)));
   
                         //Calculamos resultados
                         Ra = (L*(0.5*pi*pow(r,2)-pow(r,2)*asin(a/r)-h*(sqrt((r*r)-(a*a)))))-V;
                         Rb = (L*(0.5*pi*pow(r,2)-pow(r,2)*asin(b/r)-h*(sqrt((r*r)-(b*b)))))-V;
                         
                         //Actualizamos intervalos
                         if((Ra*f) < 0)
                           b = h;
                         else
                           a = h;
                           
                           }
       cout << "Practica 3.2 - Elementos de Programacion\n\n" <<"Solucion= " << h << "\n\n";
       system ("pause");
       return(0);
       }
       


¿Alguien podría ayudarme con lo que posteé en el mensaje anterior, lo de declarar una funcion?
Saludos y gracias. [ginyo]
En el primer cálculo de h de dentro del bucle Rb y Ra son 0, con lo que tienes de nuevo una división por cero.

Edit: y un poco más abajo, calculando Ra, en determinada iteración, se intenta calcular el arco seno de un número negativo, lo cual no existe.
melado escribió:Edit: y un poco más abajo, calculando Ra, en determinada iteración, se intenta calcular el arco seno de un número negativo, lo cual no existe.


Se puede calcular el arco seno de cualquier valor entre [-1, 1].
GameZelda escribió:Se puede calcular el arco seno de cualquier valor entre [-1, 1].

No, si cuando dije que el cálculo no era lo mío... [qmparto]

En realidad lo que ocurría era que en determinado momento se calculaba el arco seno de -1,18algo, y eso sí que no existe :P
A ver, danos el enunciado y será más fácil hacer un programa que te haga lo que te piden que buscar los fallos.

Entiendo que se trata de buscar una solución a una ecuación no lineal continua en R usando el método de la regla falsa. Debes buscar hacer el error más pequeño que un número arbitrario para obtener la solución con una determinada precisión. Expón el enunciado a ver si vemos más claro cuál es la variable independiente, etc...
Mira, sería así (espero no equivocarme que es muy tarde :P), por cierto, todavía te seguirá fallando por lo que han comentado que al ser Ra y Rb iguales a 0, el cálculo de "h" dentro del bucle while te sale la indeterminacion 0/0 y te dará otra vez NaN. Lo ideal es ver con más detenimiento el enunciado (jarkr está en la primera página) mañana a ver si lo miro. Esto más que nada es pa que veas como se haría la función ok?:

/*
  Nombre: Prácticas de Tablero 3.2
  Nick: lamateporunyogur
  Fecha: 25/10/09 20:37
  Descripcion: Aplicación de la práctica 3.2 de Elementos de Programación.
 
  Problema: Por más que lo intento, el resultado es una indeterminación.
  No consigo reducir el valor de h hasta uno menor a 10^(-3).
  O me da indeterminación, o me da 0. Espero que pueda exponer la solución.
*/

#include <iostream>
#include <cmath>

using namespace std;

//Declaramos la función "funcion_f"
double funcion_f(int L,double r, double X, double h, double V; //Sustituye "funcion_f" por "lo_que_sea"

//Función principal
main(void) {
       double h;
       double V, error, max, f, r, a, b;
       double Ra, Rb; //Resultados f(a) y f(b)
       int L;

     //Inicializamos las variables declaradas
       r=1;
       h=0;
       L=10;
       V=12.4;
       error=1;
       max=0.001;
       a=0;//h debe ser menor que el radio, y por ello está entre 0 y 1.
       b=1;
       Ra=0;
       Rb=0;
       
       f = funcion_f(L,r,h,h,V); //Calculamos "funcion_f" (sustituir por el mismo "lo_que_sea")
       
      //Obtenemos "h" (este bloque también podrías meterlo en otra función)
       while(error>max){
                         //Función principal
                         h = (a-(Ra*(b-a)/Rb-Ra));
   
                         //Actualizamos error
                         error = (fabs((h-V)*(h-V)));
   
                         //Calculamos resultados
                         Ra = funcion_f(L,r,a,h,V); //Calculamos "funcion_f" (sustituir por el mismo "lo_que_sea")
                         Rb = funcion_f(L,r,b,h,V); //Calculamos "funcion_f" (sustituir por el mismo "lo_que_sea")
                         
                         //Actualizamos intervalos
                         if((Ra*f) < 0)
                           b = h;
                         else
                           a = h;
                           
                           }
       cout << "Practica 3.2 - Elementos de Programacion\n\n" <<"Solucion= " << h << "\n\n";
       system ("pause");
       return(0);
       }

double funcion_f(int L,double r, double X, double h, double V) //Sustituye "funcion_f" por el mismo "lo_que_sea"
{
      double resultado = 0, pi=3.14159; //He trasladado la variable pi a esta función puesto que no la necesitas en ningún otro lado

      resultado = (L*(0.5*pi*pow(r,2)-pow(r,2)*asin(X/r)-h*(sqrt((r*r)-(X*X)))))-V;
      return resultado;
}
       


Una función o la declaras primero y después la implementas, o puedes implementarla directamente (sin declararla) pero tiene que estar colocada (implementada) antes de su uso (es decir, si usas la función X en otra función Y, X tiene que estar implementada antes que Y).

Luego tienes que poner tantos parámetros como sea necesario para que sea lo más "genérico" posible y reutilizable. En tu caso veo que usas un "L", una "V", un "r", un "h", y luego un valor (que primero usas "h", luego "a", y luego "b"), llamemosle "X" ok?, y ya con esos parámetros, junto a variables que sean necesarias para cumplir el objetivo de la función (como por ejemplo el número pi, que si te das cuenta solo te hace falta para eso, así que mejor declararlo dentro de la función), los combinamos con las operaciones necesarias y creamos la función. Por último devolvemos el resultado de dichas operaciones (en este caso, puesto que es una función y no un procedimiento...).

Si quieres, para practicar, puedes hacer otra función para el bucle "while" y sacarlo de la función principal. Algo así:

h = funcion_solucion(max, error, ...);

Implementas la función "funcion_solucion" con los parámetros que veas conveniente y pruebas. Ya nos cuentas ^^.

saludos!

PD: Yo diría incluso que ese while se puede hacer una función recursiva, pero eso ya es mucha tela por ahora xD.

EDITO: Mirando por encima del enunciado, hay una cosa que me mosquea... por qué pones:

Ra = (L*(0.5*pi*pow(r,2)-pow(r,2)*asin(a/r)-h*(sqrt((r*r)-(a*a)))))-V;

En lugar de asin(a/r)-a*.... Viendo el enunciado, la definición de la función V, reemplazas h por cualquier valor y se tiene que reemplazar en toda aparición de h no?. En fin, mañana se mira con más detenimiento que es tarde xD
A ver, perdonad que no me haya fijado en que el enunciado estaba dado. Bueno, ante todo, meticulosidad y concentración al 100% a la hora de programar, que luego cuesta mucho ver los fallos. Por ejemplo, lo que te apunta ercea de la función tiene razón. Un resultado muy bueno (con más "resolución" de la que te piden) es 0.166166, por si te sirve de orientación. Con ese valor sale prácticamente clavao. Como el método se usa para funciones de una variable, puedes hacer el resto de variables como globales, y así las llamadas a la función son más sencillas (pasas un argumento sólo).

Igual te aclara hacer una prueba de la primera iteración a mano y con calculadora, para ver claramente los pasos a dar antes de ponerte a escribir el código. La verdad es que tiene su enjundia. Si saco un rato me miro el código a ver.
ercea escribió:Mira, sería así (espero no equivocarme que es muy tarde :P), por cierto, todavía te seguirá fallando por lo que han comentado que al ser Ra y Rb iguales a 0, el cálculo de "h" dentro del bucle while te sale la indeterminacion 0/0 y te dará otra vez NaN. Lo ideal es ver con más detenimiento el enunciado (jarkr está en la primera página) mañana a ver si lo miro. Esto más que nada es pa que veas como se haría la función ok?:

/*
  Nombre: Prácticas de Tablero 3.2
  Nick: lamateporunyogur
  Fecha: 25/10/09 20:37
  Descripcion: Aplicación de la práctica 3.2 de Elementos de Programación.
 
  Problema: Por más que lo intento, el resultado es una indeterminación.
  No consigo reducir el valor de h hasta uno menor a 10^(-3).
  O me da indeterminación, o me da 0. Espero que pueda exponer la solución.
*/

#include <iostream>
#include <cmath>

using namespace std;

//Declaramos la función "funcion_f"
double funcion_f(int L,double r, double X, double h, double V; //Sustituye "funcion_f" por "lo_que_sea"

//Función principal
main(void) {
       double h;
       double V, error, max, f, r, a, b;
       double Ra, Rb; //Resultados f(a) y f(b)
       int L;

     //Inicializamos las variables declaradas
       r=1;
       h=0;
       L=10;
       V=12.4;
       error=1;
       max=0.001;
       a=0;//h debe ser menor que el radio, y por ello está entre 0 y 1.
       b=1;
       Ra=0;
       Rb=0;
       
       f = funcion_f(L,r,h,h,V); //Calculamos "funcion_f" (sustituir por el mismo "lo_que_sea")
       
      //Obtenemos "h" (este bloque también podrías meterlo en otra función)
       while(error>max){
                         //Función principal
                         h = (a-(Ra*(b-a)/Rb-Ra));
   
                         //Actualizamos error
                         error = (fabs((h-V)*(h-V)));
   
                         //Calculamos resultados
                         Ra = funcion_f(L,r,a,h,V); //Calculamos "funcion_f" (sustituir por el mismo "lo_que_sea")
                         Rb = funcion_f(L,r,b,h,V); //Calculamos "funcion_f" (sustituir por el mismo "lo_que_sea")
                         
                         //Actualizamos intervalos
                         if((Ra*f) < 0)
                           b = h;
                         else
                           a = h;
                           
                           }
       cout << "Practica 3.2 - Elementos de Programacion\n\n" <<"Solucion= " << h << "\n\n";
       system ("pause");
       return(0);
       }

double funcion_f(int L,double r, double X, double h, double V) //Sustituye "funcion_f" por el mismo "lo_que_sea"
{
      double resultado = 0, pi=3.14159; //He trasladado la variable pi a esta función puesto que no la necesitas en ningún otro lado

      resultado = (L*(0.5*pi*pow(r,2)-pow(r,2)*asin(X/r)-h*(sqrt((r*r)-(X*X)))))-V;
      return resultado;
}
       


Una función o la declaras primero y después la implementas, o puedes implementarla directamente (sin declararla) pero tiene que estar colocada (implementada) antes de su uso (es decir, si usas la función X en otra función Y, X tiene que estar implementada antes que Y).

Luego tienes que poner tantos parámetros como sea necesario para que sea lo más "genérico" posible y reutilizable. En tu caso veo que usas un "L", una "V", un "r", un "h", y luego un valor (que primero usas "h", luego "a", y luego "b"), llamemosle "X" ok?, y ya con esos parámetros, junto a variables que sean necesarias para cumplir el objetivo de la función (como por ejemplo el número pi, que si te das cuenta solo te hace falta para eso, así que mejor declararlo dentro de la función), los combinamos con las operaciones necesarias y creamos la función. Por último devolvemos el resultado de dichas operaciones (en este caso, puesto que es una función y no un procedimiento...).

Si quieres, para practicar, puedes hacer otra función para el bucle "while" y sacarlo de la función principal. Algo así:

h = funcion_solucion(max, error, ...);

Implementas la función "funcion_solucion" con los parámetros que veas conveniente y pruebas. Ya nos cuentas ^^.

saludos!

PD: Yo diría incluso que ese while se puede hacer una función recursiva, pero eso ya es mucha tela por ahora xD.

EDITO: Mirando por encima del enunciado, hay una cosa que me mosquea... por qué pones:

Ra = (L*(0.5*pi*pow(r,2)-pow(r,2)*asin(a/r)-h*(sqrt((r*r)-(a*a)))))-V;

En lugar de asin(a/r)-a*.... Viendo el enunciado, la definición de la función V, reemplazas h por cualquier valor y se tiene que reemplazar en toda aparición de h no?. En fin, mañana se mira con más detenimiento que es tarde xD

Gracias ercea.
A esto es a lo que me refería desde el principio, pero siempre me daba error al compilar.
Yo la declaraba como double f (int L...). ¿Acaso es necesario la "_" para que se reconozca como funcion?
Ahora mismo no tengo tiempo para probarlo, pero esto es lo que quería hacer.

Saludos [ginyo]
PD: En cuanto al h de Ra, si, me colé. [+risas]
Pues entonces, si es como dije, la función f debería ser así:

double funcion_f(int L,double r, double X, double V);

double funcion_f(int L,double r, double X, double V) //Sustituye "funcion_f" por el mismo "lo_que_sea"
{
      double resultado = 0, pi=3.14159; //He trasladado la variable pi a esta función puesto que no la necesitas en ningún otro lado

      resultado = (L*(0.5*pi*pow(r,2)-pow(r,2)*asin(X/r)-X*(sqrt((r*r)-(X*X)))))-V;
      return resultado;
}


Y las llamadas a función:

f = funcion_f(L,r,h,V);
Ra = funcion_f(L,r,a,V); //Calculamos "funcion_f" (sustituir por el mismo "lo_que_sea")
Rb = funcion_f(L,r,b,V);

Antes puse "X" y "h" porque veia que usabas h en todas las llamadas, pero al tratarse de un error, si usas a, reemplazas cada aparición de h por "a", ídem con "b". Así que sobra un parámetro.

Sobre lo de "_" no sé muy bien a qué te refieres, de todos modos, el _ lo uso como separador (ya que ni una variable ni una función puede contener espacios). Otro truco es intercambiar mayúsuclas y minúsculas (en lugar de funcion_f, pues funcionF), el caso es que sea fácilmente visible xD, que cuando tengas 10.000 líneas te mareas xD.

PD: Todavía está pendiente que tenga que mirar el enunciado... que tiene su guasa xD. A mi Métodos Numéricos es que se me dio muy mal xDDD

saludos ;)

EDITO: Se me olvidaba decir (y ayer también) que el consejo que ha dado jarkr sobre realizar primero en papel el ejercicio es muy bueno, sobre todo en los inicios de la programación. Suele funcionar si escribes en papel el procedimiento que sigues para resolver el problema... y poco a poco te vas dando cuenta de cosillas (en plan "huy repito siempre estos pasos... así que esto podría ir dentro de un bucle... y cuando paro? ah pues paro cuando el error es mayor que "max", pues entonces esta podría ser la condición del bucle").
Creo que ya tengo dominado lo de las funciones. Gracias ercea. Mirad, he practicado con el siguiente ejercicio de programación, ya que este no me da tiempo a terminarlo y a entregarlo. De todos modos el siguiente es muy parecido, pero sin lo de aproximar.

sesion10.pdf (85.36 KB)

Ejercicio 10 en PDF

Mira, creo que he aprendido bien lo de las funciones. [risita]
EDIT: Código limpiado un poco y arreglados algunos detallitos. Ahora sí que manejo bien lo de las funciones.
// Source code written by lamateporunyogur.
#include <iostream>
#include <cmath>

#ifndef M_PI
#define M_PI (3.1415926535897932384626433832795)
#endif

using namespace std;

float funcion_f(float t)
{
   return sin(2*M_PI*t);
}

float segunda_derivada(float t)
{
    return -4*M_PI*M_PI*funcion_f(2*M_PI*t);
}

float funcion_final(float a, float b)
{
   return ( (b-a) * funcion_f((a+b)/2) ) + ( segunda_derivada((a+b)/2) * pow(b-a,3) / 24 );
}

int main ()
{
   float a, b, valor = 0;

   for(int i = 0; i < 100; i ++)
   {
      a = (float)i * 0.01;
      b = a + 0.01;
      valor += (funcion_final(a,b));
   }

   cout << "================================================================"<<endl<<"##################  Practicas de tablero: 3.4  #################"<< endl<<"##################  Elementos de Programacion  #################"<< endl<<"================================================================"<<endl<<"####################   by lamateporunyogur   ###################"<< endl<<"================================================================"<<endl;
   cout << "\n\n                  Valor de la integral: "<<valor<<"\n\n"<<endl;
   
   getchar();
   
   return 0;
}


Saludos [looco]

PD: El siguiente ejercicio es imposible, ahora lo pongo en un mensaje nuevo. [boing]
Buenas, perdona que no mire con detenimiento el ejercicio (El enunciado y eso vamos) por la hora que es (ultimamente estoy que no paro xD). A primera vista, las funciones tienen buena pinta. Me alegro mucho que le estés pillando el truco ;). Si acaso veo que usas Pi en varios sitios (en varias funciones).

Como siempre, contra menos tengas que repetir el mismo paso mejor xD (Es decir, contra mas puedas reutilizar algo aprovéchalo). En este caso, declaras como un parámetro más a tus dos primeras funciones "pi=3.14159". Como he dicho, no he mirado el enunciado, pero ¿siempre será pi=3.14159 en esas funciones?. Si es así, en lugar de pasarlo como parámetro, si siempre va a valer Pi, pues lo suyo es declararlo como una constante. Tal que así:

#define PI 3.14159

Así, por un lado te ahorras pasar como parámetro un valor que siempre será constante, y por otro, no repites lo de "pi=3.14159", sino que lo defines una vez y lo reutilizas. Es más, este tipo de constantes casi siempre se aconseja definirlas así, por lo mismo.

Ahora bien, si son funciones en las que no tiene porque valer 3.14159, sino que puede ser cualquier valor, pero por defecto valdrá 3.14159, pues entonces así está bien ;).

saludos!

EDITO: He leido por encima el enunciado y creo que perfe ^^. Una última cosilla, el enunciado te da un valor "epsilon" (epsilon = (a+ b) / 2). Aquí, lo ideal sería que declararas, en la función final, una variable "epsilon" igual a lo que te dice (algo como "float epsilon = (a+b)/2"). Ya que realmente es una variable, solo que el enunciado en sí te da un valor... pero imagina que tienes un apartado b) que te diga "Ahora resuelvelo para epsilon = (a - b) / 2". Tal y como lo tienes, tendrias que ir sustituyendo en la función cada aparición de "(a+b)/2" por "(a-b)/2". En cambio, con lo de la varaible, sustituyes por "float epsilon = (a-b)/2" y yasta. Perdona si parezco muy tikismikis eh ;).
33 respuestas