matka5432 Temat założony przez niniejszego użytkownika |
» 2018-02-15 01:29:48 Dla float chciałbym otrzymać wartość 7, dla double wartość 15. Prościej już nie potrafię. Późna pora. Za pomocą algorytmu który opisałem (ze sprawdzaniem czy 1 + 1/2^n jest reprezentowalne), dla float otrzymuję wartość 23, ale jest to liczba po przecinku w systemie dwójkowym, więc teraz wystarczy zrobić log10(2^23) z zaokgrągleniem do góry i dostaję wartość 7, czyli liczbę miejsc znaczących we float w systemie dziesiętnym. Ale czy sposób w jaki ja sprawdzam reprezentowalność, jest poprawny? |
|
jankowalski25 |
» 2018-02-15 11:09:22 Temat Zly wynik dodawania float, pierwsza strona, post P-168232. Wyrażenie std::numeric_limits < typDanych >::digits10 powinno zwrócić to, co trzeba. Dla float prędzej będzie to sześć niż siedem, chociaż w sumie to zależy od implementacji. log10(2^23) z zaokgrągleniem do góry |
Dlaczego nie w dół? Przecież 2 23 wynosi 8388608, a to jest mniejsze od 10 7 (czyli nie zadziała dla wszystkich siedmiocyfrowych liczb). Ale czy sposób w jaki ja sprawdzam reprezentowalność, jest poprawny? |
Jeśli tworzysz własny typ zmiennoprzecinkowy, to może mieć trochę sensu, ale jeśli korzystasz z float , double albo long double , to przecież wszystko zależy od implementacji, więc lepiej po prostu pobrać wynik z std::numeric_limits niż próbować to ręcznie liczyć (w dodatku błędnie i nieprzenośnie, bo jest spora szansa, że przeoczysz jakiś drobny szczegół, poza tym dla każdej implementacji obliczenie tego może wyglądać nieco inaczej). Dopisano:Zakładając, że chcesz, aby to działało dla dowolnego typu zmiennoprzecinkowego (własnego lub wbudowanego), to i tak pewnie zechcesz przeciążyć odpowiednio std::numeric_limits w celu uzyskania uniwersalnego rozwiązania. |
|
nanoant20 |
» 2018-02-15 16:24:17 look https://randomascii.wordpress.com/2012/03/08/float-precisionfrom-zero-to-100-digits-2/ |
|
geceves |
» 2018-02-15 17:25:05 Witam, w jaki sposób mogę wyznaczyć dokładność (czyli liczbę cyfr dziesiętnych z jaką reprezentowane są liczby) nieznanej zmiennej.
|
Liczbę cyfr dziesiętnych ustalić dla typu można za pomocą: std::numeric_limits::digits10 Miałem taki pomysł, aby zapisać do zmiennej wynik dzielenia 1/3 = 0.(3), a następnie mnożyć ją w pętli przez 10, dopóki ostatnia cyfra części całkowitych tej liczby jest równa 3.
|
Wydaje mi się, że próbujesz wyznaczyć epsylon, a możesz go poznać tak: std::numeric_limits::epsilon (Chciałbym zaimplementować taką funkcję, nie chcę gotowych)
|
|
|
jankowalski25 |
» 2018-02-15 21:37:19 @nanoant20: Tak, ale to zależy od implementacji. Jeśli precyzja wynosi sześć cyfr dziesiętnych, to znaczy, że każda liczba w postaci abcdef, gdzie litery od a do f oznaczają poszczególne cyfry, może być jednoznacznie zamieniona na łańcuch znaków i z powrotem na liczbę bez utraty tych sześciu cyfr. Do tego jeszcze dochodzi kropka dziesiętna, która może być w jednym z siedmiu miejsc (i wtedy to zawsze zadziała). To, o czym można przeczytać na wskazanej stronie, dotyczy szukania specjalnych wartości, które pod daną implementacją pozwolą na otrzymanie innej liczby cyfr znaczących. Problem w tym, że to nie jest przenośne - pod inną implementacją te same wartości mogą dać zupełnie inne wyniki, więc nie należy na tym polegać. Jeszcze co do tej kropki: tak, jeśli liczba jest bardzo mała lub bardzo duża, to oczywiście może się okazać, że liczba cyfr znaczących pod daną implementacją będzie inna. Prawidłowa, bezstratna konwersja jest zagwarantowana tylko wtedy, gdy kropka znajduje się obok jednej z cyfr znaczących. W innych przypadkach to może zadziałać, ale nie musi (bo zależy od implementacji), co nie zmienia faktu, że 1,23456*10 1000 ma wciąż tylko sześć cyfr znaczących. Chciałbym zaimplementować taką funkcję, nie chcę gotowych |
To zaimplementuj w całości własną klasę do obsługi liczb zmiennoprzecinkowych. W takim przypadku bazowanie na niecałkowitych typach wbudowanych nie jest dobrym pomysłem, ponieważ przy innej implementacji Twoja metoda wykonująca tego rodzaju obliczenia może się okazać nieskuteczna. |
|
nanoant20 |
» 2018-02-16 14:14:36 @jankowalski25 tak, masz rację, W temacie: \Zly wynik dodawania float\ faktycznie wprowadziłem w błąd tamtego użytkownika, ale nie zrobiłem tego umyślnie. Po prostu przeczytałem artykuł i tego nie sprawdziłem. 'mea culpa mea maxima culpa'. Zweryfikowałem swój zasób wiedzy i przyswoiłem podesłane przez Ciebie rozwiązanie std::numeric_limits < float >::digits10 |
Thanks. Jeżeli chodzi o ten artykuł, to należy traktować go bardziej jako ciekawostkę. |
|
jankowalski25 |
» 2018-02-16 20:19:08 Z ciekawości wyprowadziłem odpowiedni wzór i doszedłem do wniosku, że teoretycznie 32-bitowy float mógłby mieć osiem dziesiętnych cyfr znaczących, ponieważ 2 32 wynosi 4294967296, co jest mniejsze od 1682436097 (tyle mi wyszło wszystkich możliwych kombinacji dla ośmiu dziesiętnych cyfr znaczących - oczywiście biorę pod uwagę same liczby, bez nieskończoności i innych specjalnych dodatków). W praktyce takich implementacji się chyba nie spotyka, ale z matematycznego punktu widzenia wszystkie ośmiocyfrowe wartości z klasycznego kalkulatora można tutaj zmieścić. Wzór na liczbę wartości dla N dziesiętnych cyfr znaczących: k( n ) = pow( 9, 1 ) + pow( 9, 2 ) +...+ pow( 9, n - 1 ); f( 0 ) = 1; f( 1 ) = 36; f( n ) =(( 9 * pow( 10, n - 1 ) - k( n ) ) *( n + 1 ) + k( n ) ) * 2; g( n ) = f( 0 ) + f( 1 ) +...+ f( n ); Wynik końcowy określa funkcja g( n ) . Przykładowe wyniki: g( 0 ) = 1; g( 1 ) = 37; g( 2 ) = 541; g( 3 ) = 7201; g( 4 ) = 90649; g( 5 ) = 1096849; g( 6 ) = 12899701; g( 7 ) = 148529521; g( 8 ) = 1682436097; g( 9 ) = 18810740017; Przykład: według tego wzoru istnieje 37 dziesiętnych liczb z jedną cyfrą znaczącą. Są to: A = { - 9, - 8, - 7, - 6, - 5, - 4, - 3, - 2, - 1 }; B = { - 0.9, - 0.8, - 0.7, - 0.6, - 0.5, - 0.4, - 0.3, - 0.2, - 0.1 }; C = { 0 }; D = { 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9 }; E = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; result = A + B + C + D + E; Dopisano:Przykładowa implementacja takiego formatu, gdyby komuś było to potrzebne: Układ w pamięci: [bit znaku][położenie kropki][wartość dziesiętna]Przykładowo: możemy uzyskać osiem cyfr znaczących zajmując 32 bity, z czego pierwszy będzie bitem znaku, drugi określi położenie kropki (potrzeba 9 pozycji, nadmiarowo mamy 16), a trzeci przechowuje wartość (od 0 do 2 27, czyli 134217728). Możemy na przykład uznać, że położenie kropki przyjmuje wartości od 0 do 8, a nasza liczba należy do przedziału od 0 do 99999999. Pozostałe wartości można wykorzystać do innych celów (nieskończoność i cała reszta dodatków). Pewnie da się to jeszcze jakoś bardziej skompresować i na przykład wyliczać, która to liczba i tak to zapisywać. Wtedy można byłoby oszczędzić ten jeden bit i mieć osiem cyfr znaczących w typie float na 31 bitach, ale nie warto tego robić ze względu na złożoność obliczeniową. |
|
1 « 2 » |