Pagina 1 di 2

[C++] programma sommatoria con ciclio

MessaggioInviato: 02/07/2018, 13:25
da zerbo1000
Un approssimazione di $pi$ di “grado $n$” può essere calcolata tramite la somma
$ pi_i=sum_(j=0)^i (-1)^j*4/(2j+1) $
1. Sviluppare un programma che prenda un numero intero, $n$, e calcoli l’approssimazione di “grado $n$”.
2. Sviluppare una seconda versione che prenda un double, $epsilon$, e calcoli un approssimazione di $pi$ di “grado
$n$” tale che $|pi_i - pi_(i-1)|<epsilon$

il primo punto è cosi è funziona:
Codice:
#include <iostream>
#include <cmath>
using namespace std;


int main() {

double pi=0;

int j=0,x;
cout<<"dammi il grado dell approssimazione";
cin>>x;

while (j<=x){
   
   pi=pi+((pow(-1,j)*4)/((2*j)+1));
   j++;
}

cout<<pi;

return 0;
}

ho dei problemi con il secondo punto:

ho provato con cicli annidati per calcolare le somme e metterle in relazione con la richiesta di $| |<epsilon$
$diff=4-3/4$ è il primo termine della differenza di sommatorie, ho dei problemi con l'indice i in quando non saprei come dargli una fine, visto che la fine è il relazione con la soddisfazione della $| |<epsilon$

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

int main() {

double pi=0,pi1=0,e,diff=4-3/4;
int i,j=0;

cin>>e;

while (diff<e) {

while (j<=i){   pi=pi+((pow(-1,j)*4)/((2*j)+1));      j++;     }

while (j<=i){  pi1=pi1+((pow(-1,j-1)*4)/((2*(j-1))+1));  j++;  }

diff=pi-pi1;

}

cout<<diff;

return 0;

}

Re: [C++] programma sommatoria con ciclio

MessaggioInviato: 03/07/2018, 11:00
da Super Squirrel
Sono un po' arrugginito in matematica, ma non dovrebbe essere

$ |pi_i-pi_(i-1)|=4/(2i+1)<epsi=>i>2/epsi-0.5 $ ??

Quindi $ n $ può essere ottenuto arrotondando per eccesso il suddetto valore.

Re: [C++] programma sommatoria con ciclio

MessaggioInviato: 03/07/2018, 13:29
da vict85
Quello è il valore matematicamente corretto. All'atto pratico dovresti tenere conto che i valori sono in floating point, quindi la somma potrebbe convergere prima di quell'\(i\). E suppongo che il \(-0.5\) possa essere ignorato o sostituito con un diverso metodo di arrotondamento.

Re: [C++] programma sommatoria con ciclio

MessaggioInviato: 03/07/2018, 15:22
da zerbo1000
cosa intendi che bisogna tener conto che sono floating point all atto pratico?
se scrivo il programma con quella condizione non funziona?
ho scritto questo ma qualsiasi double che scrivo mi esce sempre 0,
i double li scrivo con il . esempio 0.06 ; come ide uso DEV c++


Codice:
#include <iostream>
#include <cmath>
#include <stdlib.h>
#include <stdio.h>

using namespace std;

int main() {

double pi=0,e;
int j;

cout<<"dammi epsilon";
cin>>e;

 
 
for(j=0;j<=2/e-1/2;j++) { pi=pi+(pow(-1,j)*4)/((2*j)+1) }


cout<<pi;

}


Re: [C++] programma sommatoria con ciclio

MessaggioInviato: 03/07/2018, 20:46
da Super Squirrel
ho scritto questo ma qualsiasi double che scrivo mi esce sempre 0,
i double li scrivo con il . esempio 0.06 ; come ide uso DEV c++

Strano che quel codice compila, manca un ";" nel corpo del ciclo for. Fatta questa correzione cmq a me il programma sembra funzionare, quindi non saprei dirti qual è il problema.
In ogni caso la condizione
Codice:
j<=2/e-1/2

andrebbe sostituita con
Codice:
j<=ceil(2/e-1/2)

affinché la disequazione $ |pi_i - pi_(i-1)|<epsilon $ sia rispettata.

Questo è il programma che avevo scritto io:
Codice:
#include <iostream>
#include <math.h>

using namespace std;

double pi(const unsigned int n)
{
    double p = 0;
    for(unsigned int i = 0; i <= n; ++i)
    {
        p += pow(-1, i) * 4 /(2 * i + 1);
    }
    return p;
}

int main()
{
    double e;
    cout << "epsilon -->";
    cin >> e;
    unsigned int n = ceil(2 / e - 0.5);
    cout << "n = " << n << endl;
    e = pi(n);
    cout << "pi(n) = " << e << endl;
    e -= pi(n - 1);
    if(e < 0)
    {
        e = -e;
    }
    cout << "|pi(n)-pi(n-1)| = " << e;
}

Re: [C++] programma sommatoria con ciclio

MessaggioInviato: 03/07/2018, 23:50
da vict85
Vorrei far notare che in C++ 1/2 è di tipo int ed è uguale a \(0\).

Per valori positivi, che è quello che ci aspettiamo, j <= std::ceil(a - 0.5 ) è equivalente a j <= std::round( a ). Inoltre usare pow per la potenza di -1 è ridicolo. Personalmente trovo che sia usato troppo dagli studenti di informatica. Da notare inoltre che ceil ritorna un valore di tipo double.

Comunque la mia preoccupazione sull'epsilon del double era inutile: la convergenza è molto molto lenta.

Il risultato di questi commenti è il seguente:
Codice:
#include <iostream>
#include <cmath>

#include <chrono>

#include <limits>

double pi(const long n, double& last_error)
{
   double p = 0;
   double eps = 1.;
   double den = 0.25;
   double elem = 0.;
   for (long i = 0; i <= n; ++i)
   {
      elem = 1 / den;
      p += (eps * elem);
      eps *= -1.;
      den += 0.5;
   }
   last_error = elem;
   return p;
}

double pi2(const long n, double& last_error)
{
   double p = 0.;
   double el = 0.;
   for (long i = 0; i <= n; ++i)
   {
      el = pow(-1, i) * 4. / (2. * i + 1.);
      p += el;
   }
   return p;
}

int main()
{
   const double min_epsilon = 4. / std::numeric_limits<long>::max();
   double e;
   std::cout << "epsilon = ";
   std::cin >> e;
   if (e < min_epsilon)
   {
      e = min_epsilon;
      std::cerr << "ERRORE: valore di epsilon troppo piccolo, l'epsilon sara' " << e << std::endl;
   }
   long n = std::lround(2. / e);
   std::cout << "n = " << n << std::endl;
   auto now = std::chrono::high_resolution_clock::now();
   double res = pi(n, e);
   auto end = std::chrono::high_resolution_clock::now();
   std::cout << "pi(n) = " << res << std::endl;
   std::cout << "|pi(n)-pi(n-1)| = " << e << std::endl;
   std::cout << "time = " << std::chrono::duration<double, std::milli>(end - now).count() << "ms" << std::endl;
   now = std::chrono::high_resolution_clock::now();
   res = pi2(n, e);
   end = std::chrono::high_resolution_clock::now();
   std::cout << "pi(n) = " << res << std::endl;
   std::cout << "|pi(n)-pi(n-1)| = " << e << std::endl;
   std::cout << "time = " << std::chrono::duration<double, std::milli>(end-now).count() << "ms" << std::endl;
}


Tutti quei chrono e le due funzioni sono state messe per mostrare come usare pow abbia una forte influenza nelle performance. Per esempio, in debug e sul mio portatile lentissimo, ho avuto il seguente risultato (compilato con Visual Studio 2017 Community ed. con sottosistema Console e per x86):
Codice:
epsilon = 1E-7
n = 20000000
pi(n) = 3.14159
|pi(n)-pi(n-1)| = 1e-07
time = 824.768ms
pi(n) = 3.14159
|pi(n)-pi(n-1)| = 1e-07
time = 4862.78ms
Premere un tasto per continuare . . .
Con il minimo epsilon che ho messo i tempi sono molto lenti.

Puoi fare ancora meglio della funzione da me proposta. Per esempio questa sembra essere un po' più performante:
Codice:
double pi(const long n, double& last_error)
{
   double p = 0;
   double eps = 1.;
   double den = 0.25;
   double elem = 0.;
   for (long i = 0; i <= n; ++i)
   {
      elem = 1. / den;
      p += elem;
      den += 0.5;
      if (i++ == n) break;
      elem = 1. / den;
      p -= elem;
      den += 0.5;
   }
   last_error = elem;
   return p;
}
e suppongo si possa fare ancora meglio.

Re: [C++] programma sommatoria con ciclio

MessaggioInviato: 30/09/2019, 15:36
da Planets
Ciao a tutti,

Non capisco perché nel primo punto mi da errore nella formula del pi e mi dice "cannot convert complex double to double assignment ".

Grazie

Re: [C++] programma sommatoria con ciclio

MessaggioInviato: 30/09/2019, 23:30
da apatriarca
@Planets: A quale codice stai facendo riferimento? Potresti mostrare le righe di codice e il relativo errore? Di solito problemi del genere possono essere dovuti alla mancanza di un punto e virgola, all'overloading di un operatore/funzione ad un tipo diverso da quello in cui ci si aspetta o ad un errore di disattenzione (scrivere per esempio qualcosa come 1.i al posto di un 1.f).

Re: [C++] programma sommatoria con ciclio

MessaggioInviato: 02/10/2019, 12:15
da Planets
Il programma riguarda il primo punto dell'esercizio ed è:

Codice:
//Program that calculates the approximation of pi greek of degree n.
#include <iostream>
#include <cmath>

using namespace std;

int main ()

{
double pi;
int j, n;

cout << "Scrivere il grado dell'approssimazione:\n";
cin >> n;

while (j<=n) {

j=0;
pi=pi+((pow(-1,j))*4/(2j+1));
j++;

}

  return 0;   // indicate that program ended successfully
}
// end function main


e mi da questo errore in corrispondenza della formula del pi: pi=pi+((pow(-1,j))*4/(2j+1)).

Re: [C++] programma sommatoria con ciclio

MessaggioInviato: 03/10/2019, 17:17
da apatriarca
Hai scritto
Codice:
2j
invece che
Codice:
2 * j
. Senza il prodotto diventa un numero complesso (il numero immaginario \(2\,i\)).