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

Zamiana ułamka dziesiętnego na binarny. Dodatkowe 0.000001 w wyniku, nie wiem skąd.

Ostatnio zmodyfikowano 2014-11-14 19:31
Autor Wiadomość
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:

C/C++
#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?
P-120214
1aam2am1
» 2014-11-09 16:45:20
Jest to pewnie spowodowane niedokładnością liczb niecałkowitych.
P-120216
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ść?
P-120219
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.
P-120222
michal11
» 2014-11-09 17:27:18
Prawdopodobnie double nie jest w stanie więcej pomieścić na części ułamkowej.
P-120223
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.
P-120228
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...
P-120304
Piastlis
» 2014-11-14 19:31:21
Cześć.
Po pierwsze w algorytmie masz błąd.
Masz:
C/C++
if( ulam > 1 )
a powinno być:
C/C++
if( ulam >= 1 )
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.
C/C++
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ę:
C/C++
{
   
    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

P-120600
« 1 »
  Strona 1 z 1