Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

Typy w C - Reprezentacja liczby float

Damian7546 16 Cze 2015 08:46 1365 30
  • #1 16 Cze 2015 08:46
    Damian7546
    Poziom 21  

    Witam,

    Jak zamienić liczbę w hex 0x4288 zakodowaną jako float w ten sposób:

    Typy w C - Reprezentacja liczby float

    na normalną liczbę dziesiętną ? Powinna to być wartość około 68,5 .

    Najpierw trzeba zamienić bajty czyli wyjdzie 0x8842, i co dalej?

    0 29
  • #2 16 Cze 2015 10:19
    kinggustav
    Poziom 19  

    Jeżeli już musisz zamieniać bajty (w pamięci są zapisywane w kolejności młodszy-starszy) to masz tu liczbę 32 bitową czyli 4 bajtową. Czyli najpierw zamieniasz pary bajtów a potem dwa razy same bajty. Moim zdaniem będzie 0x88420000, ale dawno się tak nie bawiłem, może teraz (procesory 64 bitowe) jest jakoś inaczej.
    Zależy jednak jeszcze jak brzmi zadanie, może reprezentację bajtów w pamięci możesz pominąć.
    Robi się za dużo kombinacji, i nie widzę żadnej, która dawałaby coś koło tej liczby, którą podałeś, może robię jakiś błąd.
    Najlepiej podaj poszczególne bajty w kolejności od najstarszego (bez żadnego przestawiania), przynajmniej będzie jednoznacznie.

    0
  • #3 16 Cze 2015 12:23
    szelus
    Specjalista - Mikrokontrolery

    Ten "sposób zakodowania" to standardowa reprezentacja liczb float wg. normy IEEE-754, używana praktycznie wszędzie.
    Tyle, że wartość hex jaką podałeś jest niekompletna, powinno być 0x42880000 (32 bity), co daje dokładnie 68, natomiast 68,5 to by było 0x42890000.
    Tu sobie możesz pokombinować.

    0
  • #4 16 Cze 2015 12:28
    Damian7546
    Poziom 21  

    Wartość odczytywana z termometru po modbusie to "17036" czyli w hex 0x428C .

    I jest to transmitowane w float... czyli liczbie 32bit, jest to temperatura około 69 stopni ..

    Dodano po 3 [minuty]:

    jak wyświetlić tego float'a np funkcją printf żeby otrzymać tą liczbę około 70 ?

    1
  • #5 16 Cze 2015 13:00
    szelus
    Specjalista - Mikrokontrolery

    Float-owe 0x438C0000 to 70 dziesiętnie.
    Nie wiem, co czytasz, może niepoprawnie czytasz. Widać, że to co odczytujesz to starsze 16 bitów tej liczby float, nie mam pojecia, co się dzieje z młodszymi bitami. Może w protokole modbusowym ktoś doszedł do wniosku, że nie ma co wysyłać młodszych bitów, bo termometr nie ma takiej rozdzielczości i i tak by tam były same zera?

    Jeżeli tak jest, to można zrobić jakoś tak (nic nie piszesz o środowisku):

    Kod: c
    Zaloguj się, aby zobaczyć kod

    0
  • #6 16 Cze 2015 13:25
    Damian7546
    Poziom 21  

    Odpalam to w nowym projekcie, i wyświetla 0.:

    Kod: c
    Zaloguj się, aby zobaczyć kod

    0
  • #7 16 Cze 2015 13:46
    -psiak-
    Poziom 32  

    Kod: c
    Zaloguj się, aby zobaczyć kod
    http://ideone.com/C3Tig9

    @szelus - kod który podałeś nie musi działać poprawnie, ponieważ kompilator C może sobie "ubzdurać" (bo ma prawo) że do stosu nie rzucamy float'ów tylko double i już, zresztą zobacz sam na ideone już to nie konwertuje się poprawnie.

    0
  • #8 16 Cze 2015 13:54
    kinggustav
    Poziom 19  

    A czy unsignet int nie jest u Ciebie przypadkiem 16 bitowy? To by wyjaśniało te 0.

    1
  • #9 16 Cze 2015 13:55
    szelus
    Specjalista - Mikrokontrolery

    :arrow: -psiak- Zgoda, rzeczywiście poprawnie by było:

    Kod: c
    Zaloguj się, aby zobaczyć kod

    -edit-
    I kolega kinggustaw ma rację. Nie używa się typów int/unsigned to takich rzeczy. Czy ja napisałem w kodzie powyżej "unsigned"?

    0
  • #10 16 Cze 2015 13:57
    Damian7546
    Poziom 21  

    szelus napisał:
    Zgoda, rzeczywiście poprawnie by było:
    Kod: c
    Zaloguj się, aby zobaczyć kod



    Tak to wyrzuca jakąś ogromną liczbę .

    0
  • #11 16 Cze 2015 13:58
    -psiak-
    Poziom 32  

    @szelus - to to zupełnie co innego zrobi. ;)

    0
  • #12 16 Cze 2015 13:58
    Damian7546
    Poziom 21  

    @-psiak-
    Twój przykład działa tak jak oczekiwałem. Możesz mi to wyjaśnić, lub jakoś rozpisać:
    *(float*)&value

    i podać różnicę jakie są z tym
    (float)value

    ?

    0
  • #13 16 Cze 2015 14:00
    szelus
    Specjalista - Mikrokontrolery

    @-psiak- Znowu zgoda, dzisiaj mam dzień "pomroczności jasnej". :wink:

    @Damian7546
    Standardowe rzutowanie z typu całkowitego na float zrobi zwykłą konwersję liczbową tzn. tak, aby wartość była jednakowa, a nie reprezentacja bitowa w pamięci. Stad konieczność użycia "po drodze" typu wskaźnikowego, aby wskazać, że trzeba inaczej interpretować zawartość pamięci. Najpierw zrzutowanie adresu zmiennej na wskaźnik do obiektu innego typu a następnie odczyt wartości spod wskaźnika.

    0
  • Pomocny post
    #14 16 Cze 2015 14:02
    -psiak-
    Poziom 32  

    *(float*)&value to:
    unsigned *a=&value;
    float *b=(float*)a;
    float c=*b;

    (float)value to:
    float c=value;

    @szelus, ale dasz namiary na dostawce towaru? ;P

    1
  • #15 16 Cze 2015 14:15
    Damian7546
    Poziom 21  

    No nieźle :) a jak zrobić takie cudo nie mając wskaźników? Np w C# mając liczbę 0x438C któa jest w tablicy ushort[] values.

    0
  • #16 16 Cze 2015 14:21
    szelus
    Specjalista - Mikrokontrolery

    Damian7546 napisał:
    ushort[] values

    No i od tego (oraz że chodzi o C#) trzeba było zacząć, a nie dajesz nam zagadki do rozwiązania. ;)
    Bez wskaźników można użyć unii. C# nie znam, ale wg google-a było by to coś takiego:
    Kod: csharp
    Zaloguj się, aby zobaczyć kod

    A potem wypisujesz t.ftemp

    0
  • #17 16 Cze 2015 14:39
    Damian7546
    Poziom 21  

    A używając wskaźników w C#?

    0
  • #18 16 Cze 2015 14:54
    szelus
    Specjalista - Mikrokontrolery

    A w C# są wskaźniki? Jakoś mi się nie wydaje...

    0
  • #20 16 Cze 2015 17:22
    szelus
    Specjalista - Mikrokontrolery

    No to coś takiego:

    Kod: csharp
    Zaloguj się, aby zobaczyć kod

    Może jednak byś się zdecydował na jakiś język? ;)

    0
  • #21 17 Cze 2015 01:56
    -psiak-
    Poziom 32  

    Lepiej zapisać do MemoryStream unsigned po czym odczytać float.

    0
  • #22 17 Cze 2015 08:44
    alagner
    Poziom 25  

    szelus napisał:
    Damian7546 napisał:
    ushort[] values

    No i od tego (oraz że chodzi o C#) trzeba było zacząć, a nie dajesz nam zagadki do rozwiązania. ;)
    Bez wskaźników można użyć unii. (...)


    Wiem, że zeszło na C#, ale słowo komentarza: to zależy od konkretnego przypadku/toolochania, gcc pozwala na konwersję typów przy pomocy unii, ale standard tego nie definiuje.

    Tak samo - o ile pamiętam - niezdefiniowany jest cast z float* na int* (mimo, że w większości przypadków to zadziała ok).

    0
  • #23 17 Cze 2015 11:18
    szelus
    Specjalista - Mikrokontrolery

    alagner napisał:

    ... to zależy od konkretnego przypadku/toolochania, gcc pozwala na konwersję typów przy pomocy unii, ale standard tego nie definiuje.

    Tak samo - o ile pamiętam - niezdefiniowany jest cast z float* na int* (mimo, że w większości przypadków to zadziała ok).

    Oczywiście, że tak jest (tzn. tak jak mówisz). Takie sztuki, z reinterpretacją pamięci, z założenia mogą się zachowywać różnie na różnych architekturach, znaczy nie są przenośne, znaczy nie ma możliwości, aby standard wprost to definiował.

    0
  • #24 17 Cze 2015 11:57
    -psiak-
    Poziom 32  

    [quote="szelus"]

    alagner napisał:
    ... znaczy nie ma możliwości, aby standard wprost to definiował.

    Jak na razie wszędzie ten sam format dla float'a, zaś dla int'a łatwo sprawdzić czy mamy bigendian czy littleendian.

    PS
    Tak sobie pomyślałem czy nie lepiej będzie załatwić to tak:
    Kod: c
    Zaloguj się, aby zobaczyć kod
    owszem to rozwiązanie ma szereg minusów, ale to urządzenie z pewnością będzie dawać wyniki w granicach 20 - 150 może nawet węższych, przynajmniej dopóki się nie popsuje a jak się popsuje no to wszystko jedno wynik niepoprawny.
    http://ideone.com/dsDE69

    0
  • #25 18 Cze 2015 09:05
    Damian7546
    Poziom 21  

    [quote="-psiak-"]

    szelus napisał:
    alagner napisał:
    ... znaczy nie ma możliwości, aby standard wprost to definiował.

    Jak na razie wszędzie ten sam format dla float'a, zaś dla int'a łatwo sprawdzić czy mamy bigendian czy littleendian.

    PS
    Tak sobie pomyślałem czy nie lepiej będzie załatwić to tak:
    Kod: c
    Zaloguj się, aby zobaczyć kod
    owszem to rozwiązanie ma szereg minusów, ale to urządzenie z pewnością będzie dawać wyniki w granicach 20 - 150 może nawet węższych, przynajmniej dopóki się nie popsuje a jak się popsuje no to wszystko jedno wynik niepoprawny.
    http://ideone.com/dsDE69


    Próbowałem użyć twojego wzoru, ale wychodzi jakaś ogromna liczba:
    Kod: csharp
    Zaloguj się, aby zobaczyć kod

    0
  • #26 18 Cze 2015 11:01
    -psiak-
    Poziom 32  

    Kurka nawet podanego wzoru nie mogą ani zastosować ani poprawnie przepisać :/

    Kod: c
    Zaloguj się, aby zobaczyć kod

    0
  • #27 18 Cze 2015 11:11
    Damian7546
    Poziom 21  

    -psiak- napisał:
    Kurka nawet podanego wzoru nie mogą ani zastosować ani poprawnie przepisać :/
    Kod: c
    Zaloguj się, aby zobaczyć kod


    Panie, wychodzi dokładnie ta sama wartość co u z mojego kodu :):) -8448 :)

    0
  • #28 18 Cze 2015 11:16
    -psiak-
    Poziom 32  

    Jeżeli:
    x<<16
    daje to samo co:
    x>>16
    oznacza to tylko jedno: - x ma wartość zero.
    Poza tym coś Waść chrzani, bo najpierw: - "duża liczba", a teraz - nie duża ale ujemna.

    Poza tym:

    Damian7546 napisał:

    string s = txtReadRegisterValue.Text;
    uint i = uint.Parse(s);
    double ttemp = Convert.ToDouble(0.5*(i >> 16));
    double k = ttemp - 8448.0;

    txtReadRegisterValue.Text = "\r\n" + k.ToString();
    dla mnie to wygląda podejrzanie, czy ne robisz przypadkiem tego w pętli?

    Zanim napisałem temat zamknięto, więc doklejam tu (skoro już napisałem):

    Jeżeli 0.5*(uint.Parse(txtReadRegisterValue.Text)<<16)-8448.0 daje 557932288
    to rozwiązując równanie z jedną niewiadomą dostajemy że w txtReadRegisterValue.Text było zapisane 17027 (czyli 0x4283 w postaci szesnastkowej).
    Zaś na początku tematu Waść chrzanił że liczby są w postaci 0x42830000 czyli z zerami na końcu.
    Skoro nie masz już tych zer (nie wnikam czemu - ale potraktuj to jako ostrzeżenie bo coś jest nie halo) to zwyczajnie wywal to przesunięcie.

    0
  • #29 18 Cze 2015 11:38
    Damian7546
    Poziom 21  

    Nie nie, wykonuje się to tylko raz, po wciśnięciu buttona.

    Dodano po 1 [minuty]:

    Jeśli dam x<<16 to wartość mam:

    557932288

    a jeśli x>>16 to wartość

    -8448

    0
  • Pomocny post
    #30 18 Cze 2015 11:43
    szelus
    Specjalista - Mikrokontrolery

    A to nie miało być bez tego przesuwania? Bo to x to zdaje się 16 starszych bitów liczby wejściowej...

    1