Varimatras Temat założony przez niniejszego użytkownika |
Zamiana ułamka dziesiętnego na binarny. Dodatkowe 0.000001 w wyniku, nie wiem skąd. » 2014-11-09 16:07:13 Witam Piszę programy od niedawna. Próbowałem rozpisać program który miał zamienić ułamek postaci np. 0.26 na ułamek binarny. Rozpisałem więc coś co w założeniu ma po prostu mnożyć razy dwa, jeśli liczba jest większa to od jeden odejmować jedynkę, jeżeli nie to nie robić nic. Tutaj zamieszczam program: #include<stdio.h> #include<math.h> #include <conio.h> #include <iostream.h> #include<stdlib.h> #include<time.h>
int main()
{ double ulam; int i; printf( "Podaj ulamek:\n" ); scanf( "%lf", & ulam ); printf( "%lf\n\n", ulam ); for( i = 1; i < 100; i++ ) { ulam = ulam * 2; if( ulam > 1 ) { ulam = ulam - 1; printf( "%lf\t 1 \t %d\n", ulam, i ); } else { printf( "%lf \t 0 \t %d\n", ulam, i ); } } getch(); }
Dodam że na razie program nie jest "idiotoodporny" czyli uwzględnia tylko przypadek dobrze wprowadzonych danych. Próbuje więc wspomniany ułamek 0.26 Powinno dojść do okresu, tymczasem w kroku 36 zamiast pojawić się wynik 0.360000 pojawia się wynik 0.360001, nie mam pojęcia skąd te dodatkowe 0.000001 ale to oczywiście sypie całe obliczenia. Na razie moje programy wyglądają jak informatyczna wersja "Kali jeść, Kali pić" ale nie widzę niczego co by spowodowało pojawienie się tego dodatkowego 0.000001. Wspomnę jeszcze że np. przy 0.36 pojawia się -0.000001 też na 36 pozycji a przy ułamku 0.11 coś podobnego zdarza się dopiero gdzieś koło 40 kroku. Pytanie więc jest jedno, skąd te dodatkowe 0.000001, źle rozpisany program czy może inna sprawa? |
|
1aam2am1 |
» 2014-11-09 16:45:20 Jest to pewnie spowodowane niedokładnością liczb niecałkowitych. |
|
Varimatras Temat założony przez niniejszego użytkownika |
» 2014-11-09 17:15:23 To brzmi jak najbardziej sensownie ale obliczenia wydają mi się dość proste. Gdyby pojawiło się tu jakieś pi albo 2 do potęgi -1000 to owszem ale przy czymś takim niedokładność? |
|
1aam2am1 |
» 2014-11-09 17:24:09 Na informatyce miałem system zapisu liczb zmiennoprzecinkowych. Nie wiem czy taki jest obecnie stosowany ale zamiana liczby binarnej (zmiennoprzecinkowej) na system dziesiętny odbywa się w taki sposób że: Tak jak w normalnym systemie mamy kolejne potęgi dwójki, ale tym razem gdyby wziąć tylko fragment po przecinku startujemy od prawej strony i potęgi są na minusie. Potem po prosu wszystko zliczamy. Więc liczba 0.1010 to 1*2^(-1) + 0*2^(-2) + 1*2^(-3) + 0*2^(-4) = 1/2 + 0 + 1/8 + 0 = 5/8 = 0,625
To się nazywa bodajże dokładność liczb im większa tym dokładniejsze wyniki możemy uzyskać. Na tych 4 bitach nie dodamy np. 0,002 bo nie da się uzyskać 0.627 na 4 bitach.
Wiec to jest pewnie tego wina. |
|
michal11 |
» 2014-11-09 17:27:18 Prawdopodobnie double nie jest w stanie więcej pomieścić na części ułamkowej. |
|
Varimatras Temat założony przez niniejszego użytkownika |
» 2014-11-09 18:05:02 Przeczytałem to co napisane tutaj, doczytałem dodatkowo to co Internet mi podpowiada i choć wciąż jeszcze nie rozumiem na 100% to wiem już mniej więcej o co chodzi. Wciąż jednak pozostaje pytanie czy istnieje możliwość wyeliminowania tego. Wydaje mi się że obliczenia tego pokroju nie są skomplikowane i komputery powinny sobie radzić nawet z bardziej skomplikowanymi rzeczami.
Dodam może dwie rzeczy. Programik piszę sam dla siebie, robię tzw. sztukę dla sztuki ale zależy mi na tym ponieważ docelowo chciałbym napisać coś co zamieni mi dowolną liczbę dziesiętną na standard IEEE 754 liczby binarnej. Jak teraz nie działa to nie ma co ruszać dalej. |
|
Monika90 |
» 2014-11-10 15:54:16 Można wczytać część całkowitą do jednej zmiennej całkowitej, część ułamkową do drugiej. Część całkowitą zamienić na binarną jakimś tradycyjnym sposobem, a częśc ułamkową potraktować jak ułamek postaci d...d/1...0 i wyznaczyć tyle cyfr rozwinięcia binarnego ile się chce algorytmem wzorowanym na dzieleniu pisemnym znanym ze szkoły. Np. jeżeli częśc ułamkowa to 00123 to wyznaczasz rozwinięcie binarne ułamka 123/100000, które jest równe 0.00000000010100001001101111111001110001100010101000011011010111 0001111100110110001001100010110010111010011100110010110111110101... |
|
Piastlis |
» 2014-11-14 19:31:21 Cześć. Po pierwsze w algorytmie masz błąd. Masz: a powinno być: Różnica jest taka że jak skonwertowana liczba ma się skończyć na 100000 kończy się okresem 011111. Po drugie nie wiem skąd Twój szacunek błędu na 1e-6.Błąd jest ale nie w tym miejscu.6 pozycji to domyślna wartość wyświetlanych cyfr ułamkowych. printf( "%0.20f \t 1 \t %d\n", ulam, i );
I teraz widać co się naprawdę dzieje: Podaj ulamek: 0.26 0.260000
0.52000000000000002000 0 1 0.04000000000000003600 1 2 0.08000000000000007100 0 3 0.16000000000000014000 0 4 0.32000000000000028000 0 5 0.64000000000000057000 0 6 0.28000000000000114000 1 7 0.56000000000000227000 0 8 0.12000000000000455000 1 9 0.24000000000000909000 0 10 0.48000000000001819000 0 11 0.96000000000003638000 0 12 0.92000000000007276000 1 13 0.84000000000014552000 1 14 0.68000000000029104000 1 15 0.36000000000058208000 1 16 0.72000000000116415000 0 17 0.44000000000232831000 1 18 0.88000000000465661000 0 19 0.76000000000931323000 1 20 0.52000000001862645000 1 21 0.04000000003725290300 1 22 0.08000000007450580600 0 23 0.16000000014901161000 0 24 0.32000000029802322000 0 25 0.64000000059604645000 0 26 0.28000000119209290000 1 27 0.56000000238418579000 0 28 0.12000000476837158000 1 29 0.24000000953674316000 0 30 0.48000001907348633000 0 31 0.96000003814697266000 0 32 0.92000007629394531000 1 33 0.84000015258789063000 1 34 0.68000030517578125000 1 35 0.36000061035156250000 1 36 0.72000122070312500000 0 37 0.44000244140625000000 1 38 0.88000488281250000000 0 39 0.76000976562500000000 1 40 0.52001953125000000000 1 41 0.04003906250000000000 1 42 0.08007812500000000000 0 43 0.16015625000000000000 0 44 0.32031250000000000000 0 45 0.64062500000000000000 0 46 0.28125000000000000000 1 47 0.56250000000000000000 0 48 0.12500000000000000000 1 49 0.25000000000000000000 0 50 0.50000000000000000000 0 51 0.00000000000000000000 1 52
Błąd się pojawia gdzieś na 45 -50 pozycji.Czyli gdzieś 1e-15. 2e-16 jest od samego początku i w każdej pętli jest mnożony *2 . Nie jest to wina programu czy kompilatora.Współczesne pc-ty odziedziczyły to po koprocesorze numerycznym 8087 Intela i od 30 lat nikt tego nie naprawił.Najniższe cyfry w mantysie zachowują się tak jakby nie było matematyki. Jedyne co można zrobić to obciąć najniższą cyfrę: { ulam = round( ulam * 1e15 ) / 1e15; }
Komp i tak będzie liczył jak idiota ale nie będzie to miało wpływu na wynik Podaj ulamek: 0.26 0.260000
0.52000000000000002000 0 1 0.04000000000000000100 1 2 0.08000000000000000200 0 3 0.16000000000000000000 0 4 0.32000000000000001000 0 5 0.64000000000000001000 0 6 0.28000000000000003000 1 7 0.56000000000000005000 0 8 0.12000000000000000000 1 9 0.23999999999999999000 0 10 0.47999999999999998000 0 11 0.95999999999999996000 0 12 0.92000000000000004000 1 13 0.83999999999999997000 1 14 0.68000000000000005000 1 15 0.35999999999999999000 1 16 0.71999999999999997000 0 17 0.44000000000000000000 1 18 0.88000000000000000000 0 19 0.76000000000000001000 1 20 0.52000000000000002000 1 21 0.04000000000000000100 1 22 0.08000000000000000200 0 23 0.16000000000000000000 0 24 0.32000000000000001000 0 25 0.64000000000000001000 0 26 0.28000000000000003000 1 27 0.56000000000000005000 0 28 0.12000000000000000000 1 29 0.23999999999999999000 0 30 0.47999999999999998000 0 31 0.95999999999999996000 0 32 0.92000000000000004000 1 33 0.83999999999999997000 1 34 0.68000000000000005000 1 35 0.35999999999999999000 1 36 0.71999999999999997000 0 37 0.44000000000000000000 1 38 0.88000000000000000000 0 39 0.76000000000000001000 1 40 0.52000000000000002000 1 41 0.04000000000000000100 1 42 0.08000000000000000200 0 43 0.16000000000000000000 0 44 0.32000000000000001000 0 45 0.64000000000000001000 0 46 0.28000000000000003000 1 47 0.56000000000000005000 0 48 0.12000000000000000000 1 49 0.23999999999999999000 0 50 0.47999999999999998000 0 51 0.95999999999999996000 0 52 0.92000000000000004000 1 53 0.83999999999999997000 1 54 0.68000000000000005000 1 55 0.35999999999999999000 1 56 0.71999999999999997000 0 57 0.44000000000000000000 1 58 0.88000000000000000000 0 59 0.76000000000000001000 1 60 0.52000000000000002000 1 61 0.04000000000000000100 1 62 0.08000000000000000200 0 63 0.16000000000000000000 0 64 0.32000000000000001000 0 65 0.64000000000000001000 0 66 0.28000000000000003000 1 67 0.56000000000000005000 0 68 0.12000000000000000000 1 69 0.23999999999999999000 0 70 0.47999999999999998000 0 71 0.95999999999999996000 0 72 0.92000000000000004000 1 73 0.83999999999999997000 1 74 0.68000000000000005000 1 75 0.35999999999999999000 1 76 0.71999999999999997000 0 77 0.44000000000000000000 1 78 0.88000000000000000000 0 79 0.76000000000000001000 1 80 0.52000000000000002000 1 81 0.04000000000000000100 1 82 0.08000000000000000200 0 83 0.16000000000000000000 0 84 0.32000000000000001000 0 85 0.64000000000000001000 0 86 0.28000000000000003000 1 87 0.56000000000000005000 0 88 0.12000000000000000000 1 89 0.23999999999999999000 0 90 0.47999999999999998000 0 91 0.95999999999999996000 0 92 0.92000000000000004000 1 93 0.83999999999999997000 1 94 0.68000000000000005000 1 95 0.35999999999999999000 1 96 0.71999999999999997000 0 97 0.44000000000000000000 1 98 0.88000000000000000000 0 99
|
|
« 1 » |