Złożoność obliczeniowa

0

Witam!
Potrzebuje pomocy w określeniu "złożoności obliczeniowej" algorytmu liczącego liczbę Eulera jako sumy szeregu. Zamieszczam poniżej kod programu realizujący to zadanie. Czy można zoptymalizować ten algorytm ? będę wdzięczny za wskazówki, pomoc cokolwiek :)
pozdrawiam!

#include <iostream>
#include <math.h>
#include <windows.h>

using namespace std;

double suma=1, powr=1;
double wartosc_biezaca, wartosc_poprzednia, dokladnosc, zadanaDokladnosc=0.001;

int freq, start, end, diff;
double czas;

float silnia(int n);
int i=1;

int main()
{
  cout.precision(30);  
  cout.setf(ios::fixed,ios::floatfield); 
  
  wartosc_poprzednia = wartosc_biezaca = 1.0;

  QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
  QueryPerformanceCounter((LARGE_INTEGER*)&start);
   
//////////////////////////////////////////////////////////////////  
  do
  {
  powr= silnia(i);   
  suma += 1.0/powr;
  cout<< dokladnosc<<endl;
  
  wartosc_poprzednia = wartosc_biezaca;
  wartosc_biezaca = wartosc_biezaca+1/powr;
  dokladnosc = fabs(wartosc_poprzednia - wartosc_biezaca);
  
  i++;
  }while(dokladnosc>=zadanaDokladnosc);
/////////////////////////////////////////////////////////////////
  
  QueryPerformanceCounter((LARGE_INTEGER*)&end);
  diff = ((end - start) * 1000) / freq;

  unsigned int milliseconds = (unsigned int)(diff & 0xffffffff);
  cout <<"e : "<<suma;
  cout <<"  milliseconds: "<<milliseconds <<endl;

  system("PAUSE > null");
  return 0;
} 

float silnia(int n)
{
    float s=1;
    for ( int i=1;i<=n;i++)
    {
    s = s * i;
    }
    return s;
} 
0

Można zoptymalizować do czasu stałego.

0

Ten fragment

  powr= silnia(i);   
  suma += 1.0/powr;

woła o pomstę do nieba. W jednym kroku wyliczysz np. 33!, a w następnym by wyliczyć 34! będziesz znów mnożył 123*...34 zamiast wykorzystać znane 33! i policzyć tak 34!=3433!. Program nie powinien zawierać funkcji liczącej silnię.

0

Świetnie, dzięki!
Program nie powinien zawierać funkcji, która liczy silnię ? to co proponujesz ? tablice z wyliczonymi wartościami czy jak ?

0

http://www.ideone.com/VHP21

Pisany na szybko, niestabilny numerycznie, ale coś tam sensownego wypluwa.

EDIT:
Chociaż nie jest tak źle, 15 cyfr po przecinku jest dobrych :)

0

Rewelka! dziękuje bardzo. Ja to sobie przerobiłem na moje potrzeby tak:

 
#include <iostream>
using namespace std;

main(){ 
cout.precision(15);  
cout.setf(ios::fixed,ios::floatfield); 

static const int LIMIT = 1000;

double e = 1;
int i = 1;
double f = 1.;
		
while (i < LIMIT)
{
 f *= 1./ i;
 e += f;
 i++;
}
cout<<e;
system("PAUSE > null");
}

A takie pytanko jaka jest złożoność obliczeniowa tego algorytmu ?
I co to znaczy, że jest niestabilny numerycznie ?
Czy jest możliwość wyświetlenia kolejnych liczb po przecinku ? stosując standardowe biblioteki...
dlaczego jak zmienie "f*=1.0 / i" na "f*=1 / i" to wynikiem algotyrmu jest 2 ?

0

Algorytm jest niestabilny numerycznie, gdy błędy zaokrągleń się propagują. W tym przypadku - sumowania ciągów - aby uzyskać najlepszą precyzję, należy zamieniać parę dwóch wartości o najmniejszym module (wartości bezwzględnej) ich sumą, aż zostanie jedna liczba. Tutaj zamieniam dwie pierwsze liczby z ciągu. Jeśli chcesz zrozumieć problem to kup sobie jakąś książkę o analizie numerycznej.

Jak zmienisz "1. / i" na "1 / i" to dostaniesz dzielenie całkowite.

0

OK. Twoja powyższa wypowiedź jest odpowiedzią na podany niżej problem:

Wyjaśnij problem – dla dużych dokładności obliczany błąd zaczyna skakać (nie jest malejący). To spostrzeżenie nie jest zgodne z intuicjami matematycznymi. Dlaczego tak się dzieje?
94751 -> 2.718267484264691 (błąd: 1.6894574628167902E-10)
94752 -> 2.7182674843999726 (błąd: 1.3528156372899502E-10)
94753 -> 2.718267484558798 (błąd: 1.5882539727840594E-10)
94754 -> 2.7182674846839965 (błąd: 1.2519851821934935E-10)
94755 -> 2.7182674848327775 (błąd: 1.4878098753001723E-10)
94756 -> 2.718267485005161 (błąd: 1.7238344085512836E-10)
94757 -> 2.7182674851439743 (błąd: 1.3881340521493257E-10)
94758 -> 2.718267485306429 (błąd: 1.6245449430130066E-10)
94759 -> 2.718267485492544 (błąd: 1.8611512331290214E-10)
94760 -> 2.7182674855879516 (błąd: 9.54076817549776E-11)

czyli to kwestia zaokrągleń!

0

Ja bym powiedział ze raczej kwestia propagacji błędów niż zaokrągleń jako takich ;]

0

ale jakich błędów ? wynikających z czego ?

1 użytkowników online, w tym zalogowanych: 0, gości: 1