[C++] programma sommatoria con ciclio

Messaggioda zerbo1000 » 02/07/2018, 13:25

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;

}
Una mente matematica cerca un fine, una mente artistica lo stabilisce.
zerbo1000
Average Member
Average Member
 
Messaggio: 594 di 625
Iscritto il: 13/04/2015, 20:29

Re: [C++] programma sommatoria con ciclio

Messaggioda Super Squirrel » 03/07/2018, 11:00

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.
Super Squirrel
Junior Member
Junior Member
 
Messaggio: 237 di 383
Iscritto il: 16/05/2013, 22:05

Re: [C++] programma sommatoria con ciclio

Messaggioda vict85 » 03/07/2018, 13:29

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.
vict85
Moderatore
Moderatore
 
Messaggio: 9324 di 10017
Iscritto il: 16/01/2008, 00:13
Località: Berlin

Re: [C++] programma sommatoria con ciclio

Messaggioda zerbo1000 » 03/07/2018, 15:22

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;

}

Una mente matematica cerca un fine, una mente artistica lo stabilisce.
zerbo1000
Average Member
Average Member
 
Messaggio: 595 di 625
Iscritto il: 13/04/2015, 20:29

Re: [C++] programma sommatoria con ciclio

Messaggioda Super Squirrel » 03/07/2018, 20:46

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;
}
Super Squirrel
Junior Member
Junior Member
 
Messaggio: 238 di 383
Iscritto il: 16/05/2013, 22:05

Re: [C++] programma sommatoria con ciclio

Messaggioda vict85 » 03/07/2018, 23:50

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.
vict85
Moderatore
Moderatore
 
Messaggio: 9328 di 10017
Iscritto il: 16/01/2008, 00:13
Località: Berlin

Re: [C++] programma sommatoria con ciclio

Messaggioda Planets » 30/09/2019, 15:36

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
Planets
New Member
New Member
 
Messaggio: 72 di 74
Iscritto il: 10/07/2016, 21:33

Re: [C++] programma sommatoria con ciclio

Messaggioda apatriarca » 30/09/2019, 23:30

@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).
apatriarca
Moderatore
Moderatore
 
Messaggio: 5298 di 5329
Iscritto il: 08/12/2008, 20:37
Località: Londra

Re: [C++] programma sommatoria con ciclio

Messaggioda Planets » 02/10/2019, 12:15

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)).
Planets
New Member
New Member
 
Messaggio: 73 di 74
Iscritto il: 10/07/2016, 21:33

Re: [C++] programma sommatoria con ciclio

Messaggioda apatriarca » 03/10/2019, 17:17

Hai scritto
Codice:
2j
invece che
Codice:
2 * j
. Senza il prodotto diventa un numero complesso (il numero immaginario \(2\,i\)).
apatriarca
Moderatore
Moderatore
 
Messaggio: 5299 di 5329
Iscritto il: 08/12/2008, 20:37
Località: Londra

Prossimo

Torna a Informatica

Chi c’è in linea

Visitano il forum: Nessuno e 9 ospiti