Części ułamkowe w różnych systemach pozycyjnych


(Lol600000065) #1

Czesc,

Mam problem zwiazany ze zrozumieniem przeliczania części ułamkowych liczb pomiędzy roznymi systemami pozycyjnymi. Robi się to przez mnożenie ułamka przez podstawę systemu i brania z tych wyników cyfry, która przeszla w wyniku mnozenia przed kropkę dziesiętną.

1 pytanie.

Na tej stronie jest to objaśnione w tym fragmencie:

I tego do końca nie rozumiem. Przecież żeby p^-1 * p zamieniło się w p^0 w przytoczonym wzorze - a więc pierwszą cyfrę przed kropką dziesiętną - oba p muszą być tą samą liczbą, czyli trzeba mnożyć ułamek przez podstawę systemu, w której sam ułamek jest zapisany. Np. 0.56 (system dziesiatkowy) stanie się 5.6 jeśli pomnożymy ułamek przez jego podstawę systemu a więc 10.

Więc dlaczego poprawne jest zamienianie ułamka w dowolnym systemie na inny docelowy system mnożąc ułamek przez podstawę tego docelowego systemu (jak chcemy zamienić na czwórkowy system to mnożymy ułamek w systemie dziesiętnym przez 4) ? Przecież podstawa p wg tego wzoru musi być jedna i ta sama, więc teoretycznie mozliwe by były TYLKO “konwersje” na ten sam system:

0.56 “z dziesiątkowego na dziesiętny” to:

0.56 * 10 = 5.6 -> bierzemy 5

0.6 * 10 = 6.0 -> bierzemy 6

i mamy 0.56.

I taką bezsensowną konwersję rozumiem bo p i p w wyrażeniu p^-1 * p to te same liczby czyli 10^-1 * 10, a nie rózne, jak np. przy zamienianiu na czwórkowy z dziesiętnego: 10^-1 * 4, czyli raz p = 10, a czasem p = 4. To bez sensu.

Mam nadzieję, że za bardzo tego nie zaciemniłem. Czy mógłby mi ktoś wytłumaczyć dlaczego pomimo nieprawidłowego stosowania tego wzoru (wg mnie, bo przecież p to stała przyjmująca jedną ustaloną wartość a nie różne) sposób zamiany dziala dobrze ?

2 pytanie.

Dlaczego np. jak zamienimy 0.6 z dziesiątkowego systemu na czwórkowy:

0.6 * 4 = 2.4 -> bierzemy 2

0.4 * 4 = 1.6 -> bierzemy 1

0.6 * 4 = 2.4 -> bierzemy 2…

czyli dostaniemy 0.2121…, to przy zamianie z powrotem na dziesiętny nie otrzymamy oryginalnej liczby tylko te same cyfry całkowite?

0.2121 * 10 = 2.121 -> bierzemy 2

0.121 * 10 = 1.21 -> bierzemy 1…

Przecież 0.2121… w czwórkowym to 0.6 w dziesiętnym…

Wiem, że można osiągnąc liczbę w systemie dziesiątkowym przez mnozenie cyfr przez wagi pozycji na ktorych te cyfry stoją, ale chciałbym się dowiedzieć dlaczego TA metoda nie zadziała.


Bylbym bardzo wdzieczny jeżeli ktos wytłumaczyłby mi te obie kwestie…


(Razi) #2

To co w jednym systemie liczbowym jest wymierne, w innym jest (względnie) niewymierne. Dla nas 0,1 jest proste i wymierne, w systemie binarnym nie jest: nie osiągniesz wartości równej 0,1 w systemie dwójkowym, jedynie wartość przybliżoną. Dwójkowe 0,0000000001 to dziesiętnym 0,0009765625. Ale jakbyś chciał zamienić 0,0000000001 z dziesiętnego na dwójkowy, to byś uzyskał nieskończonego tasiemca.

Po prostu pewne wartości, w szczególności ułamki, po konwersjach między systemami liczbowymi tracisz dokładność.

Prosty test w Pythonie:

a=0.1;

while a!=1.0: 

  a+=0.1

  print a

W “naszej matematyce” powinno wypisać od 0.2 do 0.9. A tu całkowicie pomija wartość 1.0 i leci dalej. Dlatego nie porównuje się liczb zmiennoprzecinkowych operatorami == i !=. Po prostu nie ma sensu, bo niemal zawsze wyjdzie fałsz (==) lub prawda(!=).

jakby się dodawało 0.5, 0.25, itd. problemu żadnego by nie było.


(kostek135) #3

@Autor

Po pierwsze zapomnij o tym co napisał przedmówca, bo to bzdura.

AD 1

Ten wzór nie służy do opisu liczb zmiennoprzecinkowych. W komputerze stosowany jest kodowanie przy użyciu mantysy i cechy: http://pl.wikipedia.org/wiki/Liczba_zmiennoprzecinkowa

Innymi słowy ty traktujesz typ int i double jako równoważne reprezentacji tego co widzi komputer, innymi słowy dla ciebie 4 i 4.0 to jest to samo. Wypisz bit po bicie (ewentualnie hexy) i zobaczysz, że to przedstawia dwa różne ciągi.

AD 2

Wynika z pierwszego, dokładnie to samo w drugą stronę.

Dodam, że liczby nie koniecznie muszą być kodowane IEEE-754, ale z takimi najczęściej mamy do czynienia.

@Up to nie z faktu konwersji tracisz dokładność, ale z faktu, że komputer jest maszyna dyskretyzująca, cyfrową. Pomyślmy, od 0.0 do 1.0 ile jest liczb? Continuum. A double ma określoną liczbę bajtów na zapis, czyli to już powoduje, że nie jesteśmy w stanie wszystkich liczb z tak “wąskiego” przedziału zakodować. jeśli 0.1 naprawdę zakodowane jest jako przybliżenie to akumulacja tego przybliżenia też ma wpływ, bo binarnie to nie będą te same ciągi. To jest powód że twój program “przeskoczy warunek”. 0.5 0.25 nie mają problemu, ponieważ 1/2 to 2^-1 1/4 to 2^-2, innymi słowy nie trzeba nic przybliżać masz dokładną mantysę i cechę


(Lol600000065) #4

Tak, ale na razie nie czytałem jeszcze o tym IEEE 754, na razie chcę ogarnąć własnie te prostsze zagadnienia.

Nie rozumiem za bardzo.


(kostek135) #5

Jeszcze raz punkt pierwszy

http://edu.i-lo.tarnow.pl/inf/alg/006_bin/0004.php dałeś link do nkb ( naturalny kod binarny) jego można używać tylko przy liczbach całkowitych. Może chodzi ci o inną stronę, a tę wkleiłeś omyłkowo, póki co, nie masz co ogarniać, bo nkb nijak ma się do liczb zmiennoprzecinowych.


(Razi) #6

Owszem, opisałem łopatologiczny sposób zapisu liczb ułamkowych, ale odnosi się on też do tego IEEE-754. Z pozoru prosta liczba w jednym systemie wygląda koszmarnie w drugim, nawet przy użyciu cechy i mantysy. o ile 0,1 to 1*10¯¹, to 1,1 już jest zapisywany jako 1,1*10⁰, 11=1,1*10. nie da się uzyskać pełnej dokładności.

Bardziej przyziemny przykład: Ile to 0,1 (3)? Jest to 1/3, w zapisie dziesiętnym: 0,(3) (10). Ale i tak zapiszesz ograniczoną ilość tych trójek (tu akurat użyłem oznaczenia okresu). Zamieniając z powrotem na liczbę w systemie trójkowym nie uzyskasz już 0,1 (3), tylko innego tasiemca, coś w rodzaju 0,0(2) (3), owszem procesor (gdyby działał na systemie trójkowym) mógłby to zaokrąglić do 0,1, to taka sama zasada jak 0,(9) =1, ale wykonując takie liczenie łopatologicznie bez uwzględniania tych zaokrągleń wyjdzie ci tasiemiec.

(w nawiasach po spacji napisałem podstawę systemu w którym podałem liczbę, nawiasy bezpośrednio przy liczbie - okresy)


(Lol600000065) #7

Racja, chodziło mi o tą stronę:

:arrow: http://edu.i-lo.tarnow.pl/inf/alg/006_bin/0006.php