Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: xuhipoint en 29 Marzo 2014, 01:48 am



Título: Problema con ciclos (ejercicio de pi)
Publicado por: xuhipoint en 29 Marzo 2014, 01:48 am
El ejercicio a programar es el siguiente:
Desarrolla una función que calcule el valor de π a partir de una serie indicada a
continuación, de la cual calcularemos la cantidad de términos indicados por el usuario.
π = 4 – 4/3 + 4/5 – 4/7 + 4/9 - ... ± 4/n
Mi idea fue crear el siguiente algoritmo:
Código
  1. #include <iostream>
  2. using namespace std;
  3. int main (){
  4. int b=0,a=1,i,c=0 ;
  5. int n;
  6. cout<<"Ingrese el numero"<<endl;
  7. cin>>n;
  8. if(n%2==0){
  9. cout<<"numero invalido"<<endl;
  10. }else{
  11. for(i=1;i<=n;i++){
  12. if(i%2==0){
  13. while(a<=n){
  14. b=b-(4/a);
  15.                 a=a+2;
  16. }
  17. cout<<b<<endl;
  18. }else{
  19. while(a<=n){
  20. c=c+(4/a);
  21. a=a+2;
  22. }
  23. cout<<c<<endl;
  24. }
  25. }
  26. }
  27. }
  28.  
Lo que no entiendo es porque no me da, según mi lógica y un pseudocodigo que hice eso debería funcionar...Por favor, podrían decirme en que me equivoque.


Título: Re: Problema con ciclos (ejercicio de pi)
Publicado por: engel lex en 29 Marzo 2014, 03:37 am
uff una serie de errores XD...


primero
Código
  1. if(n%2==0){
  2. cout<<"numero invalido"<<endl;

por que si es par es invalido? es una progresion, toma presicion al avanzar, la paridad no importa en valores altos...

Código
  1. int b=0,a=1,i,c=0 ;
  2. for(i=1;i<=n;i++){
  3.  if(i%2==0){
  4.    while(a<=n){
  5.      b=b-(4/a);
  6.      a=a+2;
  7.    }
  8.    cout<<b<<endl;
  9.  }else{
  10.    while(a<=n){
  11.      c=c+(4/a);
  12.      a=a+2;
  13.    }
  14.    cout<<c<<endl;
  15.  }
  16. }

el error es que es una sumatoria.... una UNICA sumatoria.... tu lo que estás haciendo son 2 sumatorias... una negativa y otra positiva... para ambos debe ser "b" el valor afectado

otra cosa...

sabemos que pi es un numero decimal, especialmente esta operación requiere de decimales... si te fijas la haces con enteros.... jamás dará resultado...




personalmente lo habría hecho así :P (super compacto XD)

Código
  1. #include <iostream>
  2. using namespace std;
  3.  
  4. int main(){
  5.    int precision, i = 0;
  6.    float pi = 4;
  7.    cout << "ingrese un grado de precision: ";
  8.    cin >> precision;
  9.    while (i++ < precision)pi += ((i%2==0?4:-4)/(1+i*2.0f));
  10.    printf ("\npi es: %.10f \n" , pi);
  11.    system("pause");
  12.    return 0;  
  13. }

desgloso un poquito:
-en la división hago algo similar a

Código
  1. if(i%2==0) {
  2.    pi = pi + (4 / (i*2.0f) );
  3. }else{
  4.    pi = pi - (4 / (i*2.0f) );
  5. }

este 2.0f es para que se force como flotante el resultado de la división, si no, la división quedará como entero (por ejemplo si haces 4/i, al ser i entero, el resultado es entero)

-en la impresión de datos no uso cout, sino printf con el valor "%.10f" esto significa que va a imprimir 10 decimales (aunque sean ceros)

espero sea de ayuda inténtalo correr con un valor de 1000000000 :P mi maquina lo corre en unos 20 seg y el valor dudo que lo puedas tener más aproximado XD


Título: Re: Problema con ciclos (ejercicio de pi)
Publicado por: leosansan en 29 Marzo 2014, 15:23 pm
El ejercicio a programar es el siguiente:
Desarrolla una función que calcule el valor de π a partir de una serie indicada a
continuación, de la cual calcularemos la cantidad de términos indicados por el usuario.
π = 4 – 4/3 + 4/5 – 4/7 + 4/9 - ... ± 4/n
..................................................
Lo que no entiendo es porque no me da, según mi lógica y un pseudocodigo que hice eso debería funcionar...Por favor, podrían decirme en que me equivoque.

* Para empezar las instrucciones:

Código
  1. if(n%2==0){
  2.  cout<<"numero invalido"<<endl;
  3.  


están de más ya que se puede pedir un número par de términos de la sucesión. Otra cosa es que los términos de la sucesión sólo contengan números impares, pero yo puedo pedir tres o cuatro términos.

* En:


Código
  1. if(i%2==0){
  2.  while(a<=n){
  3.    b=b-(4/a);
  4.    a=a+2;
  5.  }

te sobra el while. Tal como lo tienes calcularías para cada i todos los términos de la sucesión. Y en el otro while lo mismo, además no tienes por cambiar el nombre de la variable, sigue usando b en lugar de c.

* Deberías declarar como float, ya que son valores que implican el cálculo de  decimales, a las variables b y a.

* Te falta el return de la función main e indentar el código de forma correcta.

Con esto el código corregido y funcionando;

Código
  1. #include <iostream>
  2. using namespace std;
  3. int main (){
  4.  int n,i ;
  5.  float  b=4,a=3;
  6.  cout<<"Ingrese el numero de terminos: ";
  7.  cin>>n;
  8.  cout<<endl<<endl<<"a["<<1<< "]= "<<b<<endl;
  9.  for(i=1;i<n;i++){
  10.    if(i%2!=0){
  11.      b=b-(4/a);
  12.      a=a+2;
  13.      cout<<"a["<<i+1<< "]= "<<b<<endl;
  14.    }
  15.    else{
  16.      b=b+(4/a);
  17.      a=a+2;
  18.      cout<<"a["<<i+1<< "]= "<<b<<endl;
  19.    }
  20.  }
  21.  return 0;
  22. }}

También podrías habar hecho un for que recorra sólo los impares y te ahorrarías un else y el uso del operador "%":

Código
  1. #include <iostream>
  2. using namespace std;
  3. int main (){
  4.  int N,n,signo=-1 ;
  5.  float  b=1,i;
  6.  cout<<"Ingrese el numero de terminos: ";
  7.  cin>>n;
  8.  N=2*n-1;
  9.  for(i=3;i<=N;i+=2,signo*=-1)
  10.    b+=(1/i)*signo;
  11.  cout<<"Pi= " <<4*b<<endl;
  12.  return 0;
  13. }

Citar
Ingrese el numero de terminos: 9


a[1]= 4
a[2]= 2.66667
a[3]= 3.46667
a[4]= 2.89524
a[5]= 3.33968
a[6]= 2.97605
a[7]= 3.28374
a[8]= 3.01707
a[9]= 3.25237

Process returned 0 (0x0)


Claro que si de lo que se trata es de calcular Pi y no es necesario imprimir cada termino del sumatorio, podrías hacer:

Código
  1. #include <iostream>
  2. using namespace std;
  3. int main (){
  4.  int n,signo=-1 ;
  5.  float  b=1,i;
  6.  cout<<"Ingrese el numero de terminos: ";
  7.  cin>>n;
  8.  for(i=3;i<=2*n-1;i+=2,signo*=-1)
  9.    b+=(1/i)*signo;
  10.  cout<<"Pi= " <<4*b<<endl;
  11.  return 0;
  12. }

Citar
Ingrese el numero de terminos: 1000000
Pi= 3.1416

Process returned 0 (0x0)   execution time

¡¡¡¡ Saluditos! ..... !!!!


(http://st.forocoches.com/foro/images/smilies/aaaaa.gif)

  


Título: Re: Problema con ciclos (ejercicio de pi)
Publicado por: Yoel Alejandro en 29 Marzo 2014, 17:48 pm
Bueno, reconociendo el término general de la sumatoria (algo que siempre es bueno hacer):

  4 * (-1)^n
--------------
  2 * (n - 1)

para n desde 1 hasta infinito (o hasta el máximo N impuesto por el usuario), quedaría el código siguiente donde la idea (debida a leosansan en un post similar) de usar una bandera de signo que conmute de +1 a -1 en cada iteración nos evita tener que estar viendo si n es par o impar, quedaría:
Código
  1. int main()
  2. {
  3.   double numero;
  4.   int n, N;
  5.   int signo;
  6.  
  7.   cout << "numero de terminos: ";
  8.   cin >> N;
  9.   cout << endl;
  10.  
  11.   numero = 4;
  12.   signo = -1;
  13.   for ( n = 1; n <= N; i++, signo*=-1 ) {
  14.      cout << "a[" << i << "] = " << numero << endl;
  15.      numero += signo * 4. / (2*n + 1);
  16.   }
  17.  
  18.   return 0;
  19. }
  20.  

donde el punto en "4." obliga la división entre doubles en lugar de enteros (gracias de nuevo por la acotación leosansan).


Título: Re: Problema con ciclos (ejercicio de pi)
Publicado por: leosansan en 29 Marzo 2014, 20:19 pm
Amigo yoel_alejandro de corazón que todo es en plan buen rollo, nada de suspicacias, please!.

Antes que nada creo que se te fue un gazapo en la expresión:

...............................................................

  4 * (-1)^n
--------------
  2 * (n - 1)

..........................................

Creo que tu intención era poner:

Citar

  4 * (-1)^n
--------------
 (2*n - 1)


Por otro lado:

.......................................
donde el punto en "4." obliga la división entre doubles en lugar de enteros (gracias de nuevo por la acotación leosansan).


Esta vez no me ha hecho falta lo del "4.", es decir lo del punto decimal, al declarar la variable i como float.

Por otro lado, al ser el mismo problema que en el otro tema del número Pi, he observado esta vez que me puedo ahorrar dos operaciones en cada ciclo del bucle for usando 1/i donde i es impar al empezar el bucle en tres e incrementar de dos en dos:


Código
  1. ..................................
  2.  N=2*n-1;
  3.  for(i=3;i<=N;i+=2,signo*=-1)
  4.    b+=(1/i)*signo;
  5.  ......................................
  6.  

 que se corresponden con las que hacíamos en 2*n-1: una multiplicación y una resta en cada ciclo. Y teniendo en cuenta que para que la serie propuesta nos dé 3.1416 hay que tomar un millón, n=1 000 000, de sumandos, nos queda que con el nuevo for que propongo en el último mensaje, me ahorro dos millones de operaciones, de ahí que lo cambiará respecto del otro tema.

¡¡¡¡ Saluditos! ..... !!!!


(http://st.forocoches.com/foro/images/smilies/aaaaa.gif)



Título: Re: Problema con ciclos (ejercicio de pi)
Publicado por: engel lex en 29 Marzo 2014, 21:04 pm
tiempo de ejecucion... mi codigo...

Código
  1. #include <iostream>
  2. #include <windows.h>
  3. #include <time.h>
  4. using namespace std;
  5. int main(){
  6.    int precision, i = 0;
  7.    float pi = 4;
  8.    cout << "ingrese un grado de precision: ";
  9.    cin >> precision;
  10.    clock_t tStart = clock();
  11.    while (i++ < precision)pi += ((i%2==0?4:-4)/(1+i*2.0f));
  12.    printf ("\npi es: %.10f \n" , pi);
  13.    printf("Time taken: %.4fs\n", (double)(clock() - tStart)/CLOCKS_PER_SEC);
  14.    system("pause");
  15.    return 0;  
  16. }
numero introducido: 10.000.000
resultado: 3.1415970325
tiempo: 0.2270
(con 1.000.000.000 tarda 22 sec)

codigo leosansan (modif para el tiempo)

Código
  1. #include <iostream>
  2. #include <windows.h>
  3. #include <time.h>
  4. using namespace std;
  5.  
  6. int main(){
  7.    int n,signo=-1 ;
  8.    float  b=1,i;
  9.    cout<<"Ingrese el numero de terminos: ";
  10.    cin>>n;
  11.    clock_t tStart = clock();
  12.    for(i=3;i<=2*n-1;i+=2,signo*=-1)
  13.        b+=(1/i)*signo;
  14.    cout<<"Pi= " <<4*b<<endl;
  15.    printf("Time taken: %.4fs\n", (double)(clock() - tStart)/CLOCKS_PER_SEC);
  16.    system("pause");
  17.    return 0;  
  18. }
numero introducido: 10.000.000
resultado: 3.1416
tiempo: 0.0980
->anotacion... si metes 100.000.000 o más pasa más de 50 segundos sin hacer nada, me cansé de esperar


el codigo de yoel_alejando (modificado un par de errores, con "n" e "i" y que solo haga una impresion final

Código
  1. #include <iostream>
  2. #include <windows.h>
  3. #include <time.h>
  4. using namespace std;
  5.  
  6. int main(){
  7.    double numero;
  8.   int n, N;
  9.   int signo;
  10.   cout << "numero de terminos: ";
  11.   cin >> N;
  12.   cout << endl;
  13.    clock_t tStart = clock();
  14.    numero = 4;
  15.   signo = -1;
  16.   for ( n = 1; n <= N; n++, signo*=-1 ) {
  17.      numero += signo * 4. / (2*n + 1);
  18.   }
  19.   cout << "pi es: " << numero << endl;
  20.    printf("Time taken: %.4fs\n", (double)(clock() - tStart)/CLOCKS_PER_SEC);
  21.    system("pause");
  22.    return 0;  
  23. }
  24.  
numero introducido: 10.000.000
resultado: 3.14159
tiempo: 0.0960
(con 1.000.000.000 tarda 10 sec)

el codigo de  yoel_alejandro es el ganador :P quedó muy eficiente :P ya veo que hiperresumir todo no es tan bueno

chicos usen printf es por el bien de todos o bueno de todos los decimales que fueron calculados en vano! XD


Título: Re: Problema con ciclos (ejercicio de pi)
Publicado por: leosansan en 30 Marzo 2014, 03:21 am


Es por pasar el tiempo, ¡ehh!.

Las salidas de leosansan, engel lex y  yoel_alejandro por un millon, diez y mil millones, pero eso si en las mismas condiciones , incluso en el tipo de variables para lo que tuve que modificar mi código y declarar i como int, así estamos todos iguales:


(http://i1280.photobucket.com/albums/a497/leosansan/GRAFICOS1/1leosan_zps9f26445a.jpg)


(http://i1280.photobucket.com/albums/a497/leosansan/1engellex_zpse4060ad0.jpg)

(http://i1280.photobucket.com/albums/a497/leosansan/1yoel_alejando_zps62fc1c50.jpg)


(http://i1280.photobucket.com/albums/a497/leosansan/GRAFICOS1/10leosan_zps0dde5219.jpg)


(http://i1280.photobucket.com/albums/a497/leosansan/GRAFICOS1/10engellex_zps10f955cf.jpg)


(http://i1280.photobucket.com/albums/a497/leosansan/GRAFICOS1/10yoel_alejando_zpsc3739eb2.jpg)


(http://i1280.photobucket.com/albums/a497/leosansan/GRAFICOS1/1000leosansan_zpsf35506f0.jpg)


(http://i1280.photobucket.com/albums/a497/leosansan/GRAFICOS1/1000engellex_zpsef020191.jpg)


(http://i1280.photobucket.com/albums/a497/leosansan/GRAFICOS1/1000yoel_alejando_zps508437e0.jpg)

Como se ve estamos todos en un puño sin apenas diferencias.


¡¡¡¡ Saluditos! ..... !!!!


(http://st.forocoches.com/foro/images/smilies/aaaaa.gif)



Título: Re: Problema con ciclos (ejercicio de pi)
Publicado por: engel lex en 30 Marzo 2014, 03:28 am
leosansan XD lo hice por ocio XD pero a mi por alguna razon en todas las corridas la de yoel me daba unos 10 segundos menos que el mio en 1.000.000.000 y el tuyo no andaba en más de 10.000.000 D:


Título: Re: Problema con ciclos (ejercicio de pi)
Publicado por: leosansan en 30 Marzo 2014, 03:32 am
El motivo que veo es que tenia declarada i como float. Al hacerlo como int todo va sobre ruedas.

Lo cierto es lo que comenté, estamos en centésimas de diferencias. ;)



¡¡¡¡ Saluditos! ..... !!!!


(http://st.forocoches.com/foro/images/smilies/aaaaa.gif)


Título: Re: Problema con ciclos (ejercicio de pi)
Publicado por: Yoel Alejandro en 30 Marzo 2014, 18:49 pm
Vaya, ustedes sí que tienen ocio de ponerse a medir el tiempo con cada uno de los algoritmos, jaja!

Bueno, yo uso la filosofía del mínimo recurso, me parece lo más lógico declarar n como entero, pues la función que realiza es la de un entero. Tengan en cuenta que comparar dos float es más complicado, a nivel de máquina, que comparar dos enteros. Los float llevan mantisa y exponente, y supongo que nivel de bits primero se comparan los exponentes, y si son iguales se pasa a las mantisas. En cambio en los enteros se comparan todos sus bits de una vez y punto.

A pesar de ello yo hubiera supuesto que el manejo de leosansan, de sumar dos al contador n+=2 sería más eficiente que calcular 2*n+1 (suma y multiplicación incluida). Pero el ensayo demostró que fueron equivalentes, jeje, no se por qué.

Por otra parte, es cierto que resumir el código fuente no necesariamente reduce el tiempo de ejecución. Para lo segundo hay que ponerse a pensar en lo que traduce el compilador, y por ende la manera como se ejecuta el código a nivel de la máquina (los tipos de datos involucrados, etc). Es un punto que precisamente yo venía sosteniendo desde otro post.

Por supuesto, estas son cosas para entretenernos los usuarios más avanzados, no son cosas para considerar aún por la autora del tema quién está apenas comenzando a programar (algún día lo hará), jeje.

Saludos a todos  :D



Título: Re: Problema con ciclos (ejercicio de pi)
Publicado por: amchacon en 30 Marzo 2014, 20:10 pm
A pesar de ello yo hubiera supuesto que el manejo de leosansan, de sumar dos al contador n+=2 sería más eficiente que calcular 2*n+1 (suma y multiplicación incluida). Pero el ensayo demostró que fueron equivalentes, jeje, no se por qué.
La diferencia es de un ciclo, la diferencia de rendimiento es casi nula (cada segundo se hace más de 1.500.000.000 de ciclos en un procesador de 1,5 GHZ).


Título: Re: Problema con ciclos (ejercicio de pi)
Publicado por: leosansan en 30 Marzo 2014, 21:06 pm
La diferencia es de un ciclo, la diferencia de rendimiento es casi nula (cada segundo se hace más de 1.500.000.000 de ciclos en un procesador de 1,5 GHZ).

Gracias, no por darme la razón, cosa que no has hecho, sino por la explicación del por qué algo que yo creía más eficiente no se ha traducido a los hechos, al menos a la escala que los hemos realizado.

Todo lo anterior me lleva a la conclusión de que lo que llamo "piques sanos" nos hacen más sabios cuando, sabios como tu más que estimado amchacon, nos sacan de las inevitables dudas surgidas en esos piques. Sencillamente, gracias. ;)

Además yo me lo he pasado bien. Ojalá se diera las circunstancias más a menudo ya que de la exposición de distintos puntos de vista suele surgir alguna verdad más o menos indiscutible y enriquecedora para todos.



¡¡¡¡ Saluditos! ..... !!!!


(http://st.forocoches.com/foro/images/smilies/aaaaa.gif)


Título: Re: Problema con ciclos (ejercicio de pi)
Publicado por: Yoel Alejandro en 2 Abril 2014, 00:58 am
La diferencia es de un ciclo de procesador (una operación aritmética elemental) por cada repetición del "for". Eso en el último ejemplo con mil millones de repeticiones en el "for" ha debido producir una diferencia cercana a 1 segundo, que no ha sido así. Y he ahí la incógnita  :huh:, jaja.

Pero cuidado que si queremos adentrarnos en este mundo debemos sacar con exactitud las cuentas. Tengo en mente (no se si bien recuerdo) que la frecuencia de reloj de procesador no es exactamente igual a la frecuencia de las instrucciones de máquina, dependiendo del procesador una instrucción de máquina puede demorar 4 ciclos de reloj, en otros puede demorar 12 ciclos. O sea, que el procesador de 1.5Ghz en realidad computa menos de 1500 millones de operaciones por segundo. Claro, están las arquitecturas de doble núcleo que corren en paralelo, etc. En realidad, es algo difícil predecir cuánto demorará la ejecución de un programa en una máquina determinada, sólo podemos decir que son "muchos" millones por segundo  ;D