Forum Coders' city Strona Główna Coders' city
Nasza pasja to programowanie!
 

 PomocPomoc   SzukajSzukaj   UżytkownicyUżytkownicy   GrupyGrupy  RejestracjaRejestracja 
Archiwum starego forum + teoria    RSS & Panel/SideBar
 ProfilProfil   Zaloguj się, by sprawdzić wiadomościZaloguj się, by sprawdzić wiadomości   ZalogujZaloguj 

Potrzebuję szybkiej odpowiedzi na moje pytanie... Zasady

[C++] Float nie zaokrągla wyniku



 
Odpowiedz do tematu    Forum Coders' city Strona Główna -> C i C++
Zobacz poprzedni temat :: Zobacz następny temat  
Autor Wiadomość
Kel'Thuzad



Dołączył: 02 Lut 2008
Posty: 14

PostWysłany: Wto Gru 13, 2016 7:26 pm  OP    Temat postu: [C++] Float nie zaokrągla wyniku Odpowiedz z cytatem Pisownia

Witam pisze program który liczbę zmienno przecinkowa zamienia na kod szesnastkowy. Ale mam pewien problem z obliczenie części ułamkowej na kod binarny. W internecie znalazłem kilka filmów które mi pomogły z tym zagadnieniem (bo wcześniej nie wiedziałem jak ugryź temat ) i w tym filmiku był przykład 5.2 i przedstawienie liczby 0.2 w binarce to 0011 i tak w nieskończoność (odsyłam do filmu https://www.youtube.com/watch?v=n-XozGu1viM) ale u mnie program jak mnoży 0.4 * 2.0 to mam jakieś 0.7999999 a nie 0.8 i tak dalej i w pewnym miejscy program się kończy bo otrzymuje 1 a nie powinien. Wynik poprawny to 00110011001100110011001 a u mnie jest 00110011001100110011.

Kod:
/* Program to converter floating number to hexadecimal code */
#include <iostream>
#include <cmath>
#include <iomanip>
#include <math.h>

void printfloat(float);

int main()
{
    float number = 0.0;
    int  how_many_step = 0;
    std::cin >> how_many_step;
    while (how_many_step > 0)
    {
        std::cin >> number;
        printfloat( number );
        --how_many_step;
    }
    return 0;
}

void printfloat(float n)
{
//    float number = n;
//    std::cout << number << "gg" << std::endl;
//    std::cout.setf(std::ios::fixed , std::ios::basefield);
//    std::cout << number << std::endl;
//    std::string number_to_string;
//    number_to_string += std::to_string(number);
//    std::cout << number_to_string << std::endl;
    std::string s_intiger_part;
    std::string s_decimal_part;
    std::string final_binary;
    int binary_intiger[8] {};
    int binary_decimal[8] {};
    float intiger_part = 0.0;                   //czesc calkowita
    float decimal_part = 0.0;                   //czesc ulamkowa
    decimal_part = std::modf( n , &intiger_part );
    std::cout <<  "czesc calkowita" << intiger_part << " czesc ulamkowa " << decimal_part << std::endl;
    int intiger_number = intiger_part;

    int index = 0;
    do
    {
        if( intiger_number % 2 == 0 )
        {
            std::cout << "mod 0" << std::endl;
            s_intiger_part += std::to_string(0);
            intiger_number /= 2;
            if ( intiger_number == 1 )
                ++index;
        }
        if ( intiger_number % 2 == 1)
        {
            std::cout << "mod 1" << std::endl;
            s_intiger_part += std::to_string(1);
            intiger_number /= 2;
            if ( intiger_number == 1 )
                ++index;
        }
    }
    while ( index != 1 );
    for ( int i = s_intiger_part.size() ; i >= 0 ; --i )
    {
        std::cout << "dana liczba: " << s_intiger_part[i] << std::endl;
        final_binary += s_intiger_part[i];
    }
    final_binary += ".";
    index = 0;
    std::cout << "liczba: " <<  intiger_part << " w binarnym to: " << s_intiger_part << std::endl;
    std::cout << "liczba: " <<  intiger_part << " w binarnym to: " << final_binary << std::endl;
    intiger_number = 0;
    float decimal = decimal_part;
    do
    {
//        decimal *= 2.0;
        decimal = decimal + decimal;

        std::cout.setf( std::ios::fixed , std::ios::basefield );
        std::cout << std::setprecision(4);
        std::cout <<  "decimal: " << /*ceilf(decimal)*/ decimal << std::endl;
        std::cout << "binarka: " <<  s_decimal_part << std::endl;
        if ( decimal > 1 )
        {
            s_decimal_part += std::to_string(1);
            decimal -= 1.0;
        }
        else if ( decimal > 0 && decimal < 1 )
            s_decimal_part += std::to_string(0);
        else if ( decimal == 1 || decimal == 0 )
        {
            if ( decimal == 1 )
                s_decimal_part += std::to_string(1);
            else if ( decimal == 0 )
                s_decimal_part += std::to_string(0);
            ++index;
        }
        std::cout << "binarka: " <<  s_decimal_part << std::endl;
    }
    while ( index != 1 );
    std::cout << "czesc ulamkowa: " << decimal_part << " w binarnym to: " << s_decimal_part << std::endl;
}



A w wyniku dostaje coś takiego:
Cytat:
4
5.2
czesc calkowita5 czesc ulamkowa 0.2
mod 1
mod 0
mod 1
dana liczba:
dana liczba: 1
dana liczba: 0
dana liczba: 1
liczba: 5 w binarnym to: 101
liczba: 5 w binarnym to: 101.
decimal: 0.4
binarka:
binarka: 0
decimal: 0.8
binarka: 0
binarka: 00
decimal: 1.6
binarka: 00
binarka: 001
decimal: 1.2
binarka: 001
binarka: 0011
decimal: 0.4
binarka: 0011
binarka: 00110
decimal: 0.8
binarka: 00110
binarka: 001100
decimal: 1.6
binarka: 001100
binarka: 0011001
decimal: 1.2
binarka: 0011001
binarka: 00110011
decimal: 0.3999
binarka: 00110011
binarka: 001100110
decimal: 0.7998
binarka: 001100110
binarka: 0011001100
decimal: 1.6
binarka: 0011001100
binarka: 00110011001
decimal: 1.199
binarka: 00110011001
binarka: 001100110011
decimal: 0.3984
binarka: 001100110011
binarka: 0011001100110
decimal: 0.7969
binarka: 0011001100110
binarka: 00110011001100
decimal: 1.594
binarka: 00110011001100
binarka: 001100110011001
decimal: 1.188
binarka: 001100110011001
binarka: 0011001100110011
decimal: 0.375
binarka: 0011001100110011
binarka: 00110011001100110
decimal: 0.75
binarka: 00110011001100110
binarka: 001100110011001100
decimal: 1.5
binarka: 001100110011001100
binarka: 0011001100110011001
decimal: 1
binarka: 0011001100110011001
binarka: 00110011001100110011
czesc ulamkowa: 0.2 w binarnym to: 00110011001100110011

W internecie znalazłem takie funkcje jak celi i round ale tam trzeba mieć raczej albo cały czas cześć dziesiętną setna i tak dalej bo wynik trzeba cały czas dzielić.
Powrót do góry
Zobacz profil autora Wyślij prywatną wiadomość
marcin_an



Dołączył: 26 Maj 2005
Posty: 18822

PostWysłany: Czw Gru 15, 2016 5:29 am      Temat postu: Odpowiedz z cytatem Pisownia

Nie wnikam nawet w kod*, bo już same załozenia przyjęte do jego zapisania są błędne. Używasz liczb zmiennoprzecinkowych do obliczeń wymagających dokładnych wartości. W tym momencie kończy się potrzeba sprawdzania czegokolwiek więcej.

0.799999 jest prawidłowym wynikiem wyrazenia 0.4 * 2 w świecie liczb zmiennoprzecinkowych. 0.80194 zresztą też, podobnie jak nieskończenie wiele innych wartości. Niezależnie od tematu tego wątku, zapoznaj się z tym, czym liczby zmiennoprzecinkowe są, jak się ich używa i do czego służą.

Tutaj potrzebujesz zwykłych liczb stałoprzecinkowych. Może być int, ale zapewne chcesz mieć jak najdłuższy wynik, więc o wiele lepiej sprawdzi się ::std::uintmax_t z nagłówka cstdint. Przy takim podejściu minimum 60 cyfr** zapisu dwójkowego liczysz w jednym wyrażeniu w czasie stałym***. Plus ewentualnie dodatkowy kod na ładne wypisanie tego; ale jeśli nie potrzebujesz ładnego wypisania i możesz mieć wersję szesnastkową z odwrotną kolejnością cyfr, to naprawdę jest to jedna linijka. Alternatywnie możesz uzyskać dowolną liczbę cyfr powtarzając dzielenie w nieskończoność, nawet zwykłym, szkolnym algorytmem dzielenia "pod kreską".
____
* Chociaż szybki rzut oka już ujawnia wiele błędów.
** W praktyce na współczesnych, powszechnie używanych platformach tyle to będzie. W teorii jednak nie ma ograniczenia i jeśli miałbyś procesor 512-bitowy, to w jedne instrukcji dostałbyś ponad 500 cyfr. Na razie jednak takie procesory nie są powszechnie dostępne.
*** De facto w ogóle nie liczysz, bo dla stałych danych wejściowych będzie to stały wynik, który każdy sensowny kompilator obliczy i wpakuje na twardo do programu.
Powrót do góry
Zobacz profil autora Wyślij prywatną wiadomość
Wyświetl posty z ostatnich:   
Odpowiedz do tematu    Forum Coders' city Strona Główna -> C i C++ Wszystkie czasy w strefie CET (Europa)

Strona 1 z 1

 
Skocz do:  
Możesz pisać nowe tematy
Możesz odpowiadać w tematach
Nie możesz zmieniać swoich postów
Nie możesz usuwać swoich postów
Nie możesz głosować w ankietach
Możesz dodawać załączniki na tym forum
Możesz pobierać pliki z tego forum




Debug: strone wygenerowano w 0.19613 sekund, zapytan = 11
contact

| Darmowe programy i porady Jelcyna | Tansze zakupy w Helionie | MS Office Blog |