Zmienne w c++

Awatar użytkownika
Sokół
Użytkownik
Użytkownik
Posty: 451
Rejestracja: 17 wrz 2006, o 19:22
Płeć: Mężczyzna
Lokalizacja: Zielona Góra
Podziękował: 15 razy
Pomógł: 55 razy

Zmienne w c++

Post autor: Sokół »

Okej, od dwoch dni ucze sie programowania w c++. Przerabiam kurs ktory sie ukazal w ktorym expercie, dzisiaj przyszedl czas na zmienne, ale wybieglem sobie troche do przodu, bo potrzebna mi byla petla. Chcialem sobie zrobic implementacje metody leibniza do obliczania liczby pi.
\(\displaystyle{ \sum_{n=0}^{\infty} \frac{(-1)^{n}}{2n+1} = \frac{1}{1} - \frac{1}{3} + \frac{1}{5} - \frac{1}{7} + \frac{1}{9} - s = \frac{\pi}{4}}\)

jednak jak moj program wypisuje pi, to tylko 4 lub 5 miejsc po przecinku. Chcialbym, zeby tak z dwadziescia miejsc po przecinku Jak to zrobic? Kod programu;
(pisalem w devie, gdzie sie kompiluje)

Kod: Zaznacz cały

#include <iostream>
using namespace std;
int main()
{
    float pi =0;
    float mianownik;
    for(int licznik= 0; licznik< 10000; licznik++)
                 {
                    if(licznik%2==1)
                                   {
                                        mianownik=2*licznik+1;
                                        pi=pi-4/mianownik;
                                   }
                    else
                                   {
                                        mianownik=2*licznik+1;
                                        pi=pi+4/mianownik;
                                   }
              
                 }




                  cout << "pi wynosi: " << pi;
}

krotkie wyjasnienie kodu. To rozwiniecie ze wzoru pomnozylem sobie obustronnie razy cztery. A ze raz sie dodaje, a raz odejmuje, to powstal warunek ktory sprawdza modulo licznika. Mozna petle zmniejszyc, ale przyblizenie liczby pi bedzie mniej dokladne.

[ Dodano: 11 Sierpnia 2007, 02:13 ]
zmienna licznik nie oznacza licznika na gorze w ulamku! "Licznik" to jest hmmm zmienna ktora mowi ktory jest krok pętli.
luka52
Użytkownik
Użytkownik
Posty: 8601
Rejestracja: 1 maja 2006, o 20:54
Płeć: Mężczyzna
Lokalizacja: Kraków
Podziękował: 47 razy
Pomógł: 1816 razy

Zmienne w c++

Post autor: luka52 »

Zamiast zmiennych typu float użyj double lub long double choć i tak te typy mają swoje ograniczenia (tak na szybko sprawdzałem i różnica to jest chyba 1 cyfra więcej ). Jeżeli zaś bardzo zależy Ci na uzyskaniu możliwie wysokiej precyzji - zainteresuj się biblioteką GMP ... ic_Library .
bagin
Użytkownik
Użytkownik
Posty: 14
Rejestracja: 18 paź 2006, o 19:49
Płeć: Mężczyzna
Lokalizacja: Częstochowa
Pomógł: 3 razy

Zmienne w c++

Post autor: bagin »

Możesz użyć na strumieniu funkcji setprecision(), która jako argument pobiera ilość miejsc po przecinku jaka ma zostać wyświetlona. Powinno wyglądać to tak:

cout
luka52
Użytkownik
Użytkownik
Posty: 8601
Rejestracja: 1 maja 2006, o 20:54
Płeć: Mężczyzna
Lokalizacja: Kraków
Podziękował: 47 razy
Pomógł: 1816 razy

Zmienne w c++

Post autor: luka52 »

Jednak funkcja setprecision() wymaga dodatkowego pliku nagłówkowego iomanip o ile się nie mylę.
smiechowiec
Użytkownik
Użytkownik
Posty: 374
Rejestracja: 21 cze 2007, o 11:28
Płeć: Mężczyzna
Lokalizacja: Łostowice
Pomógł: 146 razy

Zmienne w c++

Post autor: smiechowiec »

można jeszcze dodać, że analogiczny efekt uzyskamy korzystając z formatowania zwykłej funkcji printf.
Dla 12 bajtowego typu long double dałoby się wycisnąć pecyzję ok 30.
Po tych uwagach Twój program dla dev-cpp

Kod: Zaznacz cały

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

int main() { 
    double pi = 0.0; 
    double mianownik; 
    for(int licznik = 0; licznik < 10000; licznik++) { 
		if( (licznik %2) ==1) { 
			mianownik = (2 * licznik) + 1;
            pi = pi - (4 / mianownik);
		} 
		else { 
			mianownik = (2 * licznik) + 1;
            pi = pi + (4 / mianownik);
		}
	}
	printf("pi wynosi: %20.18f
", pi);
	cout << "pi wynosi: " << setprecision(20) << pi; 
} 
Awatar użytkownika
Sokół
Użytkownik
Użytkownik
Posty: 451
Rejestracja: 17 wrz 2006, o 19:22
Płeć: Mężczyzna
Lokalizacja: Zielona Góra
Podziękował: 15 razy
Pomógł: 55 razy

Zmienne w c++

Post autor: Sokół »

luka52 pisze:Zamiast zmiennych typu float użyj double lub long double choć i tak te typy mają swoje ograniczenia (tak na szybko sprawdzałem i różnica to jest chyba 1 cyfra więcej :| ). Jeżeli zaś bardzo zależy Ci na uzyskaniu możliwie wysokiej precyzji - zainteresuj się biblioteką GMP :arrow: .
MS-DOS and MS Windows
On an MS-DOS system DJGPP can be used to build GMP, and on an MS
Windows system Cygwin, DJGPP and MINGW can be used. All three are
excellent ports of GCC and the various GNU tools.

`

Kod: Zaznacz cały

http://www.cygwin.com/
'
`http://www.delorie.com/djgpp/'
`http://www.mingw.org/'

Microsoft also publishes an Interix "Services for Unix" which can
be used to build GMP on Windows (with a normal `./configure'), but
it's not free software.

MS Windows DLLs
On systems `*-*-cygwin*', `*-*-mingw*' and `*-*-pw32*' by default
GMP builds only a static library, but a DLL can be built instead
using

./configure --disable-static --enable-shared

Static and DLL libraries can't both be built, since certain export
directives in `gmp.h' must be different.

A MINGW DLL build of GMP can be used with Microsoft C. Libtool
doesn't install a `.lib' format import library, but it can be
created with MS `lib' as follows, and copied to the install
directory. Similarly for `libmp' and `libgmpxx'.

cd .libs
lib /def:libgmp-3.dll.def /out:libgmp-3.lib

MINGW uses the C runtime library `msvcrt.dll' for I/O, so
applications wanting to use the GMP I/O routines must be compiled
with `cl /MD' to do the same. If one of the other C runtime
library choices provided by MS C is desired then the suggestion is
to use the GMP string functions and confine I/O to the application.
to chyba oznacza, ze na xpeku z devem 4.9.9.2 (MinGW) nie moge tego uzywac ;(
Xitami

Zmienne w c++

Post autor: Xitami »

Long double to 12 bajtów? Sprawdziłbym to, bo sądzę, że tylko 10 z czego da się "wycisnąć" około 19 cyfr, ale...
Przede wszystkim chodzi o to, że metoda Leibniz'a stosowana na wprost jest bardzo wolno zbieżna. Wykonujesz 10000 iteracji i właśnie spodziewać się możesz 4 czy 5 poprawnych cyfr. Po miliardzie uzyskasz 9 cyfr. Czyli ile razy musi "obrócić" się pętla by uzyskać 20 dokładnych cyfr? Masz tyle czasu? :-)
Ale jest na to sposób, nawet nie jeden.
Można zmienić wzór wg którego liczysz (np. Machin), albo zastosować jakąś metodę przyśpieszającą zbieżność obliczeń szeregów naprzemiennych.
Taki mój mały wynalazek (choć Euler mnie chyba uprzedził :-)
Wstępnie policz ileś tam kroków, powiedzmy \(\displaystyle{ M}\). Następnie zbierz kolejne przybliżenia w tablicy. Niech będzie ich \(\displaystyle{ N}\). Teraz poczynając od pierwszego elementu w tablicy umieść średnią bieżącego i następnego. Uzyskasz \(\displaystyle{ N-1}\) "średnich". Powtarzaj to aż w tablicy zostanie tylko jedna wartość. Będzie to całkiem fajne \(\displaystyle{ \pi}\), ale precyzja nie przekroczy możliwości użytego typu zmiennoprzecinkowego. Poeksperymentuj z M i N.
Pętlę można zapisać nieco "lżej"

Kod: Zaznacz cały

while(licznik<K){
           pi -= 1/licznik++;
           pi += 1/licznik++;
}
Potrzebne jest tylko dodawanie, odejmowanie i liczenie odwrotności, to niewiele. Można by zrezygnować z float, a liczbę pamiętać w tablicy. W kolejnych komórkach kolejne cyfry. Dodawanie i odejmowanie bajecznie proste, mały kłopot z odwrotnością ale do przejścia. Tak kiedyś policzyłem pierwsze tysiące cyfr liczby \(\displaystyle{ \pi}\).
GMP zmieni tylko tyle, że da Ci wielką precyzję, ale kłopot z powolnością metody pozostanie.
Wesołej zabawy.
Awatar użytkownika
Sokół
Użytkownik
Użytkownik
Posty: 451
Rejestracja: 17 wrz 2006, o 19:22
Płeć: Mężczyzna
Lokalizacja: Zielona Góra
Podziękował: 15 razy
Pomógł: 55 razy

Zmienne w c++

Post autor: Sokół »

Xitami pisze:GMP zmieni tylko tyle, że da Ci wielką precyzję, ale kłopot z powolnością metody pozostanie.
To był trening, tak, żeby poćwiczyć to co umiem. Żeby uzyskać szybkość zaimplementowałem metodę Ramanujana trzeci obrót pętli i dokładność chyba 16 cyfr po przecinku.
ODPOWIEDZ