[C++] Typ float a dość duże liczby


(Lol600000065) #1

czesc,

mam taki problem zwiazany z typem float. Musze operować na dużych liczbach rzędu 10^20. Wybrałem do tego celu float, ponieważ ma on zakres -/+3.4e38. Jednak gdy wpisuje tak dużą liczbę jak np. 10^20 to mi ją obcina... Najwyższą liczbę, jaką wczytuje bez obcinania jest 10^10... Żeby wczytywać wyższe muszę używać double / long double.

Jednak czemu ten float nie dziala pomimo ze ma wyzszy zakres niz 10^20 ?


(Mk Md) #2

Liczby zmiennoprzecikowe reprezentowane są w komputerze jako cecha i mantysa. Różnica między float a double jest taka że mają one różną liczbę bitów przeznaczoną na ceche i mantyse.

Jeśli moje wyjaśnienia nie są dla Ciebie wystarczające wejdź na tą strone:

http://www.icm.edu.pl/kdm/Biuletyn_nr_11


(Sawyer47) #3

A gdzie/jak wczytujesz/wpisujesz te wartości? To stałe dosłowne w kodzie czy pobierane przez IO? Tak czy siak wydaje mi się, że 1e20 nie powinno stanowić problemu dla float. Pokaż jakiś fragment kodu, który sprawia problemy.


(Lol600000065) #4

marcin_k, dzięki zaraz to przeczytam.

@up

Wartości są pobierane przez IO:

#include

([alex]) #5

http://www.cplusplus.com/doc/tutorial/variables/

Obczaj tabelkę w punkcie: Fundamental data types, kolumna Range.

float ma tylko 6-7 cyfr znaczących.

double ma 15-16 cyfr znaczących.

więc dla liczb 10^20 nawet double ci nie wystarczy, może użyj liczby 64 bitowe.


(Lol600000065) #6

A takie wchodzą oficjalnie w standard ? Muszę korzystać też tylko z biblioteki standardowej jak coś...


([alex]) #7

No to niestety musisz napisać własną klasę, bo oficjalnie niema jeszcze tego w standardzie. Ale każdy kompilator ma.


(Lol600000065) #8

No cóż trudno. Pomimo, że kazdy kompilator to ma to nie zostaly one jeszcze uwzględnione w funkcjach takich jak sqrt, printf, scanf itp...

Bedę musial rozwiazac moj problem jakos inaczej...

EDIT:

Sorry, w printf i scanf to się uda ale już w sqrt niestety nie...


([alex]) #9

Więc wystarczy że napiszesz swój sqrt.


(Lol600000065) #10

to co sadzicie o tym pomysle (max liczba cyfr w liczbie bedzie wynosic 19). (uzywam zapisu x^y bo nie chce pisac mi sie y zer)

  1. pierwsze sprawdzamy czy liczba cyfr liczby long long jest wieksza od 15 (liczbę cyfr musze znac tez po cos innego wiec 2 pieczenie na 1 ogniu):

  2. jeśli nie to po prostu konwertujemy tą liczbę na double i dajemy do sqrt - Koniec

  3. Jeśli liczba cyfr > 15, to dzielimy liczbe przez 10^10 ( gdyby liczba miala 19 cyfr (dopuszczalne max) - to nam da 9 cyfr, a to sie zmiesci w double). I potem robimy cos takiego:

    wynik = sqrt(double(podzielona_liczba)) * double(10^5);

    //To samo tylko ze dłuzej:

    //wynik = sqrt(double(podzielona_liczba)) * sqrt(double(10^10));

Dobry pomysl ?


([alex]) #11
  1. Musisz pamiętać że sqrt(liczba)*sqrt(liczba) nie da ci dokładnie tej liczby.

  2. Jak ci nie zależy na szybkości to może być tak jak piszesz, ale wg mnie spokojnie możesz użyć sqrt(liczba).

  3. Liczbę cyfr możesz uzyskać: int liczba_cyfr=abs(ceil(log10(liczba)));


(Lol600000065) #12

  1. Rzeczywiście, dla dużych liczb, częśc całkowita pierwiastka waha się nawet o 8. Czyli to rozwiązanie odpada - świetnie....

  2. Zalezy mi na szybkosci, ale przecież jak mogę użyć pojedynczego sqrt(liczba), skoro liczba jest typu long long? Sqrt nie przyjmuje tego typu.

  3. Liczbę muszę przepisać tez w pewnym celu do tablicy char, wiec wystarczy ze uzyję szybszego strlen :slight_smile:

Z góry będę bardzo, ale to bardzo wdzieczny za pomoc.


([alex]) #13

Możesz użyć sqrt(liczba) ponieważ nastąpi niejawna konwersja na long double.


(Lol600000065) #14

Rzeczywiście... No ale niby long double ma ten sam zakres co double wg cplusplus.com, czyli przed przecinkiem może mieć 15 cyfr. A moja przykładowa liczba miała ich 18. Pierwiastek wyszedł dobry, ale jak to możliwe ?


([alex]) #15

Chodzi o dokładność. Tak czy owak nawet dla liczby typu double przy niezbyt dużej liczbie:

liczba!=sqrt(liczba)*sqrt(liczba)

więc nie musisz się przejmować błędami w jakimś 10-tym znaku po przecinku bo nie ma sposobu pozbycia się niedokładności.


(Lol600000065) #16

Hehe, ale mi znaki po przecinku nie są w cale potrzebne. I tak pierwiastek bd porównywał z liczbą całkowitą (pisze algorytm dla obliczania liczb pierwszych). Dziwi mnie tylko fakt, że obiekt long double może mieć max 15 cyfr przed przecinkiem, natomiast mój obiekt long long ma ich czasem 19. Jak to możliwe że program obliczy dobry pierwiastek , skoro liczby przed przecinkiem nie powinny się pomieścic w long double ?


([alex]) #17

jeżeli masz liczbę:

1234567890123456789

to w long double ona zapisze się jako:

1.23456789012346E18

czyli w tym przypadku konwersja dodała ekstra 3211 do liczby.

dla pierwiastku to prawie nie ma znaczenia.


(Lol600000065) #18

Aaa, rozumiem. I niejawna konwersja dodatkowo sprytnie zamienia ostatnią możliwą do wczytania cyfrę (5) o 1 większą, żeby user na tym nie stracił. W moim przypadku okazało się to przydatne :smiley:

Dzieki za pomoc.