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ń.

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