precyzja float

0

Dlaczego operacja

    float x = 538.06f;
    int n = x*10000;
    cout << n <<endl;

zwraca liczbe 538099? Takie same wyniki na gcc czy msv2005

0

Wynik x10000 jest typu float. Przybliżenie do int dałoby wynik, którego oczekujesz. Ale konwersja do int nie odbywa się przez przybliżenie, ale obcięcie. Więc daj:
int n = (x
10000)+0.5;
i ciesz się prawidłowym wynikiem w każdej sytuacji.

dopisane:
z technicznego punktu widzenia ma się sprawa trochę inaczej, ale nie chce mi się wchodzić w szegóły ;P Chyba, że ci potrzebne są koniecznie

0

czesc calkowita mozna tez uzyskac tak:

float czesc_calkowita, czesc_dziesietna;
czesc_calkowita = (short) float_value;
czesc_dziesietna = float_value - czesc_calkowita;

tylko ze wtedy gdy mamy np cos takiego:

float value1 = 1.3f;
float value2 = 7.64f;
float float_value = value1 * value2;

czesc_dziesietna uzyska wartosc 0.93199921f

jest jakis sposob by temu zaradzic?

0

czesc_dziesietna uzyska wartosc 0.93199921f
jest jakis sposob by temu zaradzic?

Tzn co chcesz? Aby bylo dokladniej? To zmien float na double. A jesli chcesz jeszcze wiekszej precyzji to przejdz na jakis jezyk programowania do obliczen np Fortran77 lub lepiej Fortran 90/95...

0

czesc_dziesietna uzyska wartosc 0.93199921f
jest jakis sposob by temu zaradzic?

nie. liczby zmiennoprzecinkowe zawsze beda mialy pewna precyzje i jesli liczba nie bedzie idealnym zlozeniem poteg dwojki - pojawia sie zniesztalcenia. nawet uzywajac long double sie od tego nie uwolnisz - dostaniesz wtedy np. 0.931999999921. obejrzyj std::numeric_limits<float>, std::numeric_limits<double> (sa w naglowku 'limits')i zapoznaj sie ze zdefiniowanymi w nich stalymi - szczegolnie takie kruczki jak epsilon. tych ograniczen nie da sie przeskoczyc, tak po prostu dzialaja komputery.

uwaga: po wypisaniu liczby 0.93199921f na ekran mozesz czasem zobaczyc 0.932 - to znaczy ze procedura wypisujaca to 'zaokraglila'

uwaga2: ograniczenie MOZNA przeskoczyc - poprzez trzymanie liczb w czyms innym niz zmiennoprzecinkowce, np jako ulamki licznik/mianownik gdzie licznik i mianownik sa calkowite, albo tez jako ciagi znakow np. char* liczba = "1234.534545"; i operacje matematyczne wykonywac recznie, metodami zblizonymi liczenia w slupkach na kartce itp.itd.

0

Poczatkujacy jestem w dziedzinie prog, dlatego prosze, wytlumaczciez mi dlaczego:

    float x = 538.06f;
    int n = x*10000;
    cout << n <<endl;

wypisuje 5380599?
Powiedzcie mi w ktorym miejscu toku myslenia robie blad:

  1. Przy mnozeniu x*10000 najpierw 10000 promowane jest do typu float.
  2. Mnozone wtedy sa 2 liczby typu float - 5380.06 * 10000 = 53800600
  3. Wynik konwertowany jest do typu int.
  4. Typ float najczesciej ma 6 cyfr znaczacych - czyli mnozac 538.06 * 10000 otrzymuje 5380600 - wszystkie one sa cyframi znaczacymi, czyli nie powinienem tracic dokladnosci. Dlaczego wiec przy konwersji z float na int zamiast 5380600 otrzymuje 5380599?
    Dodatkowo, gdy wypisuje
cout << (x*10000) <<endl

to otrzymuje prawidlowy wynik na ekranie...
Wiem ze post poczatkowy troche stary, ale nie bede zakladal na to nowego watku.

0
  1. Mnozone wtedy sa 2 liczby typu float - 5380.06 * 10000 = 53800600

Problem w tym, że 583.06 przy pojedynczej precyzji to:
1,0508984 * 2^9\approx 538,0599808
Po wymnożeniu przez 10000:
1,0508984 * 2<sup>9 * 1,2207031 * 2</sup>{13} = 1,2828349 * 2^{22} = 5380599,5524096

0

Cechę której oczekujesz posiadają liczby zapisywane dziesiętnie, a nie binarnie jak float. W bibliotece standardowej nie ma takiego typu danych, ale można skorzystać z czegoś zewnętrznego o nazwie decimal/currency/money ... lub samemu coś wymyślić. Oprócz wspomnianych ułamków i ciągów cyfr można pracować na liczbach całkowitych zakładając, że każda liczba reprezentuje wielokrotność np. liczby 0.001

0

adf88, podstawa systemu liczbowego nie ma tu nic do rzeczy, każdą liczbę rzeczywistą da się reprezentować zarówno dziesiętnie jak i binarnie - naturalne podstawy są izomorficzne razem z podstawowymi działaniami. Rzeczywste dodatnie da się przedstawić nawet finarnie, to jest w base-fi. Tutaj problem tkwi w skończonej precyzji i oszczędności miejsca.

0

Nieprawda. Tu chodzi o konwersję z dec->bin w której mnożą się miejsca po przecinku, które muszą być obcięte. Często ułamek jest okresowy więc dowolnie duża precyzja tu nie wystarczy. Jeśli pracować by na typie decymalnym to precyzji by wystarczyło na powyższe obliczenia tak, aby nic nie zostało ucięte. Póki liczba ma tyle cyfr znaczących ile mantysa, to typ decymalny nie spowoduje żadnych przekłamań.

0

Ech, to nie sama konwersja jest przyczyną tego wydawałoby się dziwnego zachowania, tylko skończona precyzja, o której już wspomniałem, a która wyklucza izomorfizm między podstawami. Oczekiwany wynik pojawiałby się, gdyby liczby zmiennoprzecinkowe były podciałem ciała liczb rzeczywistych, a nim nie jest. Jeżeli masz systemy o podstawach naturalnych i nieskończonej precyzji, to niezależnie, w jakiej kolejności i w jakich podstawach będziesz dodawał lub mnożył, wynik będzie taki sam.

"nieprawda", "póki"

0

Ech, to nie sama konwersja jest przyczyną tego wydawałoby się dziwnego zachowania, tylko skończona precyzja
To i to łącznie. Jeśli precyzja byłaby nieskończona, to konwersja nic by nie obcinała. Jeśli nie byłoby konwersji, to precyzji na te obliczenia by wystarczyło. I ten drugi przypadek jest do osiągnięcia przy pomocy typu decymalnego.

pÓÓÓÓki dodajemy/odejmujemy/mnożymy liczby typu decymalnego to precyzji powinno na dość sporo wystarczyć. Przy dzieleniu/funkcjach już możemy dostać za duże rozwinięcie, o to ci chodzi ? Ja rozważam problem na podstawie działań z przykładu.

"nieprawda", "póki"
dzięki ;)

0

No dobrze, w miare rozumiem, ale jednak dalej mam pytanie:
Dlaczego ten kod wypisuje oczekiwana liczbe na ekranie, czyli 5380600, a nie 5380599?

float x = 538.06f;
int n = x*10000;
cout << (x * 10000) <<endl;

Myslalem ze powinno wypisac jednak 5380599, czyli tyle ile wynosi to w przyblizeniu, a nie wartosc taka jaka oczekuje. Czy po deklaracji float x = 538,06f w komputerze przechowywana jest, oprocz wartosci zadeklarowanej, czyli 538,06, rzeczywista wartosc zmiennej, czyli okolo 538,0599?

0

Dlaczego ten kod wypisuje oczekiwana liczbe na ekranie, czyli 5380600

Bo tu nie ma konwersji float -> int, tylko float -> tekst. Być może funkcja konwertująca (gcvt, fcvt, ecvt) zaokrągla liczbę do postaci, o której piszesz.

Czy po deklaracji float x = 538,06f w programie przechowywana jest, oprocz wartosci zadeklarowanej, czyli 538,06, rzeczywista wartosc zmiennej, czyli okolo 538,0599?

Nie. Jest tylko jedna wartość - 538,0599...

1 użytkowników online, w tym zalogowanych: 0, gości: 1