Skocz do zawartości

Float...okreslenie ilosci cyfr po przecinku


farmaceuta

Pomocna odpowiedź

Żadne bity nie znikają. To print() nie pokazuje zer nieznaczących. Przecież mając w 16-bitowej zmiennej wartość (dziesiętnie) 24 nie chiałbyś zobaczyć 00024 tylko po prostu 24, tak samo wypisując dwójkowo bajt 00010110 dostajesz na ekranie 10110.

Zrób sobie własną funkcję, która wypisze zawsze pełne 8 bitów z otrzymanego bajtu i tyle.

I jeszcze: czy pamiętasz co to są unie? To taka struktura danych, w której kolejne elementy zajmują to samo miejsce w pamięci. Jeśli więc stworzysz przykładowo taką unię:

union {
  float f;
  byte b[4];
} moja_unia;

to w tym samym miejscu będzie zmienna float i tablica bajtów. Możesz teraz (najpierw wskazujesz nazwę unii a po kropce jej element):

moja_unia.f = 50.234567;

a potem odczytać bajt po bajcie co tam naprawdę w pamięci siedzi:

for (int n=0; n<4; n++) {
  Serial.print(moja_unia.b[n], HEX);
  Serial.print(" ");
}
Serial.println();

 

  • Pomogłeś! 1
Link do komentarza
Share on other sites

Ok sprawdze to...no ale i tak cos bylo nie tak bo juz "przerobiona" zmienna long miala inna wartosc niz ta wyjsciowa (w dziesietnym systemie oczywiscie)...hmm jutro zrobie jeszcze test ale z krutkimi liczbami i zobaczymy co z tego wyniknie...dzieki wielkie za poswiecany czas i cierpliwosc:-)

Link do komentarza
Share on other sites

(edytowany)
21 minut temu, kaworu napisał:

Taka ciekawostka, wiesz, że to się wykona jako operacja na double?

Moglbys rozwinac?? ...(caly czas wieluuuuu rzeczy nie rozumiem...)

W long otrzymuje to co chcialem czyli...50123456

Edytowano przez farmaceuta
Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

10 godzin temu, farmaceuta napisał:

jesli np. starsze bity sa zerami to mi je "urywa" (przynajmniej tak to wyglada w Serial monitorze)..

Bo źle rozumiesz działanie funkcji print. Funkcja drukuje tylko znaczące cyfry, a zera po lewej pomija.

Przykładowo: jeśli masz zmienną typu long i wartość 15, to wydrukuje Ci 15 bez zer na początku, prawda?

Zapoznaj się z rodziną funkcji printf (w Twoim przypadku może to być sprintf), łap sznurek: https://www.nongnu.org/avr-libc/user-manual/group__avr__stdio.html

Przykładowo: printf("%04X", zmienna) wydrukuje Ci zawsze cztery cyfry szesnastkowe nawet jeśli wartość zmiennej będzie zerem.

Tylko uważaj, bo wersja na AVR-y (czyli również Arduino) nie działa na floatach (można ją do tego zmusić, ale to nie temat na ten wątek, zresztą już to opisywałem przy okazji jednego z robotów: 

A tak przy okazji - operatory bitowe powinny być stosowane wyłącznie do liczb unsigned, czyli nie long a unsigned long. Poza tym przyzwyczaj się do konkretnych długości (np. uint32_t zamiast unsigned long), bo przesiądziesz się na inny procesor i okaże się, że pół programu trzeba zmienić bo w Arduino int miał 16 bitów, a w ESP czy STM-ach 32.

 

  • Pomogłeś! 1
Link do komentarza
Share on other sites

1 godzinę temu, farmaceuta napisał:

Moglbys rozwinac?? ...(caly czas wieluuuuu rzeczy nie rozumiem...)

W long otrzymuje to co chcialem czyli...50123456

Jeden z argumentów operacji to double, wiec kompilator wykona promocje drugiego argumentu do double, na nich wykona operacje, i zrobi konwersje do float. Więc tak, masz to co chciałeś, ale większym kosztem jeśli nie masz FPU operującego na double. 😉

Link do komentarza
Share on other sites

Panowie (bo do wszystkich tu obecnych sie zwracam) naprawde poklony w wasza strone za cierpliwosc dla mojej osoby...(juz napewno zaczynam byc irytujacy) i wielki szacunek za wasza wiedze! moge  tylko domyslac sie ile ton ksiazek i internetu musieliscie przerobic...naprawde szacun! ;-).

A teraz tak (hehe ;-))...czego sie nauczylem? albo Arduino jest cofniete w rozwoju albo ja...(nie musicie odpowiadac!! ;-)) , ale nie za bardzo radzi sobie z liczbami z zakresu wiekszego niz 16 bitow...jezeli chce liczbe 26bit zapisanej w uint_32t bitowo wpisac do bajtow to ok...ale przy prubie odtworzenia z bajtow do  uint_32t  wszystko od 16 bita w lewo jest "uciete" i sa tam 1 lub 0...w zaleznosci od uzytej liczby np.

float polozenie1 = 66.123437;
uint32_t polozenie3 = polozenie1 * 1000000.0;  //tutaj ma 66123436

tx_buf[0] =  (polozenie3 & 0x3ffffff) >> 18 ;
tx_buf[1] =  (polozenie3 & 0x3ffffff) >> 10 ;
tx_buf[2] =  (polozenie3 & 0x3ffffff)  >> 2 ;
tx_buf[3] =  (polozenie3 & 0x3ffffff)  << 6 ;

uint32_t q = (tx_buf[0] << 18)  | (tx_buf[1] << 10) | (tx_buf[2] << 2) |  (tx_buf[3] >> 6) & 0x3ffffff;

// binarnie wygloda to tak 
11111100001111011010101100  // polozenie3
11111100001111011010101100  // poukladane juz bajty
11111111111111011010101100  // q zlozone z bajtow (od 16 biata w lewo "urywa"

dodatkowo float ktory ma wiecej niz 4 cyfry po przecinku juz moze miec blad na ostatniej cyfrze tak jak w tym przykladzie (po mnozeniu i rzutowaniu)...

ten sam kod ale inna liczba...

10101000010100010100101100  // 44123436 (przerobiony float jak wyzej)
10101000010100010100101100   // poustawiane bajty
00000000000100010100101100   // q (od 16 bita w lewo "urywa"

tym razem wyswietlalem bity prawidlowo...po tym jak mi powiedzieliscie o print() przypomnialem sobie ze juz to przerabialem i rozwiazalem za pomoca funkcji bitRead() w petli for..

dodam jeszcze tylko ze na uint16_t takich cyrkow nie mam...moge dowolnie operowac liczba ktora miesci sie w tym zakresie, i jest normalnie odtwarzana z bajtow/bitow.

Link do komentarza
Share on other sites

6 minut temu, farmaceuta napisał:

nie za bardzo radzi sobie z liczbami z zakresu wiekszego niz 16 bitow...

A to ciekawe... czasami mi się zdarza użyć int64 i jakoś sobie radzi...

7 minut temu, farmaceuta napisał:

dodatkowo float ktory ma wiecej niz 4 cyfry po przecinku juz moze miec blad na ostatniej cyfrze

Praca domowa: sprawdzić ile bitów zajmuje w float zapis wartości i obliczyć, na którym miejscu wystąpi błąd.

 

15 minut temu, farmaceuta napisał:

wszystko od 16 bita w lewo jest "uciete" i sa tam 1 lub 0...w zaleznosci od uzytej liczby

Nie od 16 a od 8, 16 albo 24, akurat trafiłeś na 16. A teraz porównaj dwa fragmenty kodu:

    uint8_t tx_buf[4];

    uint32_t polozenie3 = 66123436UL;
    
    tx_buf[0] =  (polozenie3 & 0x3ffffff) >> 18 ;
    tx_buf[1] =  (polozenie3 & 0x3ffffff) >> 10 ;
    tx_buf[2] =  (polozenie3 & 0x3ffffff)  >> 2 ;
    tx_buf[3] =  (polozenie3 & 0x3ffffff)  << 6 ;
    
    uint32_t q = (tx_buf[0] << 18)  | (tx_buf[1] << 10) | (tx_buf[2] << 2) |  (tx_buf[3] >> 6) & 0x3ffffff;
    
    printf("%08X %08X\n", polozenie3, q);

Wynik:

03F0F6AC 03F0F6AC

I drugi fragment:

    int8_t tx_buf[4];

    uint32_t polozenie3 = 66123436UL;
    
    tx_buf[0] =  (polozenie3 & 0x3ffffff) >> 18 ;
    tx_buf[1] =  (polozenie3 & 0x3ffffff) >> 10 ;
    tx_buf[2] =  (polozenie3 & 0x3ffffff)  >> 2 ;
    tx_buf[3] =  (polozenie3 & 0x3ffffff)  << 6 ;
    
    uint32_t q = (tx_buf[0] << 18)  | (tx_buf[1] << 10) | (tx_buf[2] << 2) |  (tx_buf[3] >> 6) & 0x3ffffff;
    
    printf("%08X %08X\n", polozenie3, q);

Wynik:

03F0F6AC FFFFFEAC

Praca domowa część druga: sprawdzić, czym się różnią oba fragmenty i wyjaśnić:

  1. skąd się bierze pozorny błąd
  2. dlaczego wynik obliczeń jest prawidłowy w obu przypadkach (chociaż w drugim zupełnie nie to chcieliśmy uzyskać)

Tak przy okazji: jeśli bawisz się w bity i tym podobne sztuczki musisz, powtarzam MUSISZ umieć posługiwać się zapisem szesnastkowym (najlepiej również ósemkowym) bez zastanawiania się co znaczy każda cyfra. W szczególności musisz obudzony o trzeciej w nocy umieć przerobić zapis szesnastkowy liczby na dwójkowy i vice versa.

  • Pomogłeś! 1
Link do komentarza
Share on other sites

Cos mi nie chce dzialac ten "printf" lub "sprintf" doczytalem ze musze dodac <stdio.h>  ale nic...dopiero po dodaniu biblioteki <ArduinoSTL.h> cos pokazuje ale nie tak jak powyzej, zamiast 03F0F6AC pokazuje 0000F6AC  (oryginalna zmienna)...za pomoca "Serial.println(polozenie3, HEX);" to mam 3F0F6AC i  "Serial.println(q, HEX);" FFFFF6AC

21 godzin temu, ethanak napisał:

Praca domowa: sprawdzić ile bitów zajmuje w float zapis wartości i obliczyć, na którym miejscu wystąpi blad

tu musze sie jeszcze dobrze do szkolic bo ten float to skomplikowany jest (dla mnie).

21 godzin temu, ethanak napisał:

Praca domowa część druga: sprawdzić, czym się różnią oba fragmenty i wyjaśnić:

  1. skąd się bierze pozorny błąd
  2. dlaczego wynik obliczeń jest prawidłowy w obu przypadkach (chociaż w drugim zupełnie nie to chcieliśmy uzyskac)

1. No wydaje mi sie ze z deklaracji tablicy tx_buf...w pierwszym kodzie uint8_t (0-255) a w drugim int8_t (-128-127 (czyli "zamiennik" char?))

2. Pewnie przez hmmm..no wlasnie. napewno ma to zwiazek z punktem 1.

Tylko tak..nie przeslalem calego kodu tu, a w przykladach ktore podalem wyzej tablica byla typu uint8_t  (czyli  tak jak u ethanak z prawidlowymi wynikami)

      uint8_t tx_buf[4];

    uint32_t polozenie3 = 66123436UL;
    
    tx_buf[0] =  (polozenie3 & 0x3ffffff) >> 18 ;
    tx_buf[1] =  (polozenie3 & 0x3ffffff) >> 10 ;
    tx_buf[2] =  (polozenie3 & 0x3ffffff)  >> 2 ;
    tx_buf[3] =  (polozenie3 & 0x3ffffff)  << 6 ;
    
    uint32_t q = (tx_buf[0] << 18)  | (tx_buf[1] << 10) | (tx_buf[2] << 2) |  (tx_buf[3] >> 6) & 0x3ffffff;
    
    printf("%08X %08X\n", polozenie3, q);

Wynik:

03F0F6AC 03F0F6AC

u mnie jest identycznie a wynik "q" jest bledny..

Link do komentarza
Share on other sites

28 minut temu, farmaceuta napisał:

Cos mi nie chce dzialac ten "printf" lub "sprintf" doczytalem ze musze dodac <stdio.h>  ale nic

Pokaż co próbowałeś zrobić. Jak znam życie coś pokręciłeś z rozmiarami zmiennych albo zapomniałeś przeczytać co tam piszą w podanym linku o printf/sprintf i podobnych a zwalasz na Bogu ducha winne Arduino.

Weź się lepiej trochę za czytanie jak to wszystko działa i przynajmniej próby zrozumienia, a pytania zadawaj dopiero wtedy, jak czegoś nie zrozumiesz. Niestety - jeśli będziesz przesyłał kawałki programu z pytaniami "czemu to nie działa" to w pewnym momencie ktoś odpowie "A czort[1] jego wie" i skończy dyskusję.

Zgłoś się jak Ci wyjdzie prawidłowa ośmiocyfrowa liczba szesnastkowa uzyskana z sprintf. Nawet jeśli nie będzie zgodna z oczekiwaniami. Wybacz - ale jakieś podstawy musisz mieć żeby iść dalej, a bez tego ja już nie podejmuję się jakiegokolwiek tłumaczenia.

To jeszcze takie pytanie - jak sobie wyobrażasz takie działanie:

Masz zmienną typu uint8_t. Przesuwasz ją w lewo o 18 bitów otrzymując 16-bitowy wynik (czyli unsigned int). Jak myślisz, jaką wartość powinna mieś ta zmienna żeby wynik był różny od zera?

No i pytanie kontrolne: co zrobić, żeby wynik był zgodny z oczekiwaniami (32-bitowy)?

 

 

 

  • Pomogłeś! 1
Link do komentarza
Share on other sites

No i tak...

Dnia 24.02.2021 o 19:27, ethanak napisał:

No i pytanie kontrolne: co zrobić, żeby wynik był zgodny z oczekiwaniami (32-bitowy)?

Poinformowac kompilator zeby wynik byl traktowany jako...32-bitowy.

poczytalem troche i znalazlem takie terminy jak "promocja do int" czy "jawne/niejawne rzutowanie". no i mimo ze wynik mialem jako 32bit to wyrazenie zawieralo zmienne/liczby z zakresu nie wiekszego niz 16bit i kompilator w takim wlasnie zakresie zapisal zmienna. no chyba to bylo problemem bo teraz dziala elegancko z tym ze nie rozumiem jednej rzeczy...czemu musze uzyc "jawnego rzutowania" dwa razy do dwoch pierwszych bajtow? (starsze bajty).  W niczym to nie przeszkadza, ale przeczytalem rowniez ze wystarczy w wyrazeniu uzyc np. jednej zmiennej 32bit zeby kompilator zrezygnowal z promocji do 16bit...z tym "jawnym rzutowaniem" nie powinno byc tak samo?

uint8_t tx_buf[4];

uint32_t polozenie3 = 55555555UL; 

tx_buf[0] =  (polozenie3 & 0x3ffffff) >> 18 ;
tx_buf[1] =  (polozenie3 & 0x3ffffff) >> 10 ;
tx_buf[2] =  (polozenie3 & 0x3ffffff) >> 2 ;
tx_buf[3] =  (polozenie3 & 0x3ffffff) << 6 ;

uint32_t q =  ((uint32_t)tx_buf[0] << 18) | ((uint32_t)tx_buf[1] << 10) | (tx_buf[2] << 2) | (tx_buf[3] >> 6) & 0x3ffffff ;

 

Dnia 24.02.2021 o 19:27, ethanak napisał:

Weź się lepiej trochę za czytanie jak to wszystko działa i przynajmniej próby zrozumienia, a pytania zadawaj dopiero wtedy, jak czegoś nie zrozumiesz.

Ja caly czas czytam...to nie tak ze czekam na gotowe odpowiedzi a sam od siebie nie poswiece "5 minut" zeby cos przeczytac/sprobowac zrozumiec.. pewnie .poprostu idzie mi to troche gorzej niz wiekszosci...w kazdym razie staram sie jak moge.

Link do komentarza
Share on other sites

10 godzin temu, farmaceuta napisał:

czemu musze uzyc "jawnego rzutowania" dwa razy do dwoch pierwszych bajtow? (starsze bajty)

To przeczytaj mój poprzedni post i odpowiedz wreszcie na pytanie jak zmieścić w 16 bitach liczbę przesuniętą o 18 miejsc w lewo.

Link do komentarza
Share on other sites

Cześć wszystkim dzisiaj pierwszy post bo dopiero co konto założyłem. No Panie @farmaceuta dobrze by było jakbyś troszkę zrozumiał jak działają liczby zmiennoprzecinkowe w komputerze. Polecam https://www.samouczekprogramisty.pl/liczby-zmiennoprzecinkowe/ oraz 

natomiast o ile dobrze zrozumiałem istotę twojego problemu to możesz go rozwiązać za pomocą funkcji ftoa() i liczyć ile znaków masz po przecinku. Trzeba jednak pamiętać o tym że te funkcje operują na float i double więc zajmują sporo pamięci oraz wolno działają. Na teraz mam napisaną funkcję(jak ftoa()) która pobiera float a oddaje dwa int-y jeden część dziesiętna drugi część ułamkowa. Jeśli będzie zainteresowanie to chętnie pokażę. Pozdrawiam _LM_

Edytowano przez _LM_
  • Lubię! 1
Link do komentarza
Share on other sites

Dnia 26.02.2021 o 09:23, ethanak napisał:

To przeczytaj mój poprzedni post i odpowiedz wreszcie na pytanie jak zmieścić w 16 bitach liczbę przesuniętą o 18 miejsc w lewo.

Kolego @ethanak ...czytalem wiele razy, szukalem odpowiedzi i jej nie znalazlem...temat stary, ale pasuje wiedziec o co chodzi...problem dotyczyl tego ze jesli do zmiennej uint32_t przesune bitowo bajt o wiecej niz 16 miejsc to wszystko po lewej od 16 bita "znika"...pomaga "jawne rzutowanie", ale musze rzutowac dwa razy jesli chcialbym umiescic dwa bajty po lewej stronie uint32_t a przeciez napewno da sie to zrobic prosciej...

uint32_t q =  ((uint32_t)tx_buf[0] << 18) | ((uint32_t)tx_buf[1] << 10) | (tx_buf[2] << 2) | (tx_buf[3] >> 6) & 0x3ffffff ;

Panie...zlituj sie Pan...😢 (ja naprawde dlugo szukalem odpowiedzi...)

Link do komentarza
Share on other sites

31 minut temu, farmaceuta napisał:

do zmiennej uint32_t przesune bitowo bajt o wiecej niz 16 miejsc

No to teraz pomyśl.

Przesuwasz bajt (czyli uint8_t jak mniemam).

Operacja przesunięcia podobnie jak wszystkie operacje arytmetyczne, musi w wyniku dać liczbę co najmniej n-bitową, gdzie n jest liczbą bitów w podstawowym typie int (czyli w przypadku AVR-ów będzie to 16 bitów). Zauważ: co najmniej, ale nigdzie nie jest powiedziane że musi nagle stać się szersza bo tak...

A jak sam zauważyłeś, szesnastobitowa liczba przesunięta o 16 miejsc w lewo staje się ładnym, szesnastobitowym zerem... o czym zresztą kompilator bardzo grzecznie informuje już w czasie kompilacji programu.

41 minut temu, farmaceuta napisał:

pomaga "jawne rzutowanie"

No cóż - nie znam lepszego sposobu. Zawsze sobie możesz napisać jakieś makro w stylu

#define SHL32(a,b) ((uint32_t)(a) << (b))

albo przenieść się z AVR-ów na jakąś platformę, gdzie int jest 32-bitowy i ten problem nie występuje.

 

  • Pomogłeś! 1
Link do komentarza
Share on other sites

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.