Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

Wyznaczanie dokładności nieznanej zmiennej.

Ostatnio zmodyfikowano 2018-02-16 20:19
Autor Wiadomość
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?
P-169413
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ż 223 wynosi 8388608, a to jest mniejsze od 107 (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.
P-169414
nanoant20
» 2018-02-15 16:24:17
look
https://randomascii.wordpress.com/2012/03/08/float-precisionfrom-zero-to-100-digits-2/
P-169418
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)
Frazy, które należy wpisać w wyszukiwarkę google:
P-169421
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*101000 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.
P-169427
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ę.
P-169447
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ż 232 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:
C/C++
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:
C/C++
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:
C/C++
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]
PrecyzjaZnakKropkaWartośćBitówBajtów
111461
2127102
31210132
41314183
51317213
61320243
71324284
81427324
91430355
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 227, 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ą.
P-169454
1 « 2 »
Poprzednia strona Strona 2 z 2