Kanał - ATNEL tech-forum
Wszystkie działy
Najnowsze wątki



Teraz jest 23 kwi 2024, o 13:54


Strefa czasowa: UTC + 1





Utwórz nowy wątek Odpowiedz w wątku  [ Posty: 12 ] 
Autor Wiadomość
PostNapisane: 17 paź 2018, o 14:39 
Offline
Nowy

Dołączył(a): 17 paź 2018
Posty: 13
Pomógł: 0

Witam,

mam pytanie o funkcję w języku c.

Potrzebuję namierzyć "coś" co pozwoli mi odczytać liczbę znak po znaku, czyli np. -16,3 potrzebuję rozłożyć na:
-
1
6
,
3
Żeby móc te znaki wyświetlić na wyświetlaczu led.

W innym języku znam funkcję mid(tekst, start, długość) i nie ma problemu- mogę odczytać każdy znak. Natomiast w c nie mogę znaleźć żadnego odpowiednika (jestem na początku drogi z C).

Będę wdzięczny za wskazówki.


Pozdrawiam



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 17 paź 2018, o 15:33 
Offline
Nowy

Dołączył(a): 17 paź 2018
Posty: 13
Pomógł: 0

Dzięki!

coś drgnęło, ale nie do końca.

Nie wiem jak mam podglądnąć tablicę do której wpisywane są znaki z liczby, ale znaki są inne niż być powinny.

Składnia: [ Pobierz ] [ Ukryj ]
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.


Zmienne cy są globalne.
Przy użyciu kodu jak powyżej wyskakują mi krzaki na wyświetlaczu (przy wpisaniu wartości "z ręki" wyświetlacz działa poprawnie).
Co może być przyczyną?



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 17 paź 2018, o 21:08 
Offline
Uzytkownik zasłużony dla forum.atnel.pl
Avatar użytkownika

Dołączył(a): 16 lip 2012
Posty: 2088
Lokalizacja: Leżajsk / Kraków
Pomógł: 411

zubik napisał(a):
To itoa nie pomoże bo zmienia cyfry na znaki char

Można odjąć 0x30 (48 dziesiętnie) i np. '0' zamieni się na 0, ale to tak na marginesie. Bufor do itoa powinien być o 1 większy niż spodziewany najdłuższy ciąg znaków ciąg znaków. Itoa zwraca też '-' więc to będzie 7.

_________________
Dragonus Cracovus: Biomagia



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 19 paź 2018, o 08:52 
Offline
Nowy

Dołączył(a): 17 paź 2018
Posty: 13
Pomógł: 0

Działa mi na itoa z odejmowaniem 48 w zakresie +/- liczb całkowitych.

A czy jest podobna funkcja dla liczb zmiennoprzecinkowych (double)?

I jeszcze dodatkowe pytania.
1. Co mam rozumieć przez zostawienie większego buforu na "-" w itoa?
2. Funkcja itoa jest u mnie podkreślona na pomarańczowo z komunikatem: "implicit declaration of function 'itoa' [-Wimplicit-function-declaration]". Czy mam się tym przejmować?


Pozdrawiam



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 19 paź 2018, o 09:20 
Offline
Użytkownik

Dołączył(a): 05 sty 2015
Posty: 393
Lokalizacja: Mielec
Pomógł: 14

Itoa odczytuje wszystkie znaki np minus "-" czy przecinek kropke itp



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 19 paź 2018, o 10:36 
Offline
Nowy

Dołączył(a): 17 paź 2018
Posty: 13
Pomógł: 0

No własnie o ile minus mi wykrywa o tyle wydaje się, ze kropki nie wykrywa.


EDIT:
Kropek itoa nie wykrywa (zresztą argumentem funkcji jest int, a nie double). Przy zdefiniowaniu wartości na typ większy niż int16_t funkcja sie wysypuje.


Rozumiem zatem, że jeżeli chce mieć wyświetlane liczby zmiennoprzecinkowe to zostaje mi ręczna separacja tysięcy, setek, dziesiątek itd.?



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 19 paź 2018, o 15:45 
Offline
Użytkownik

Dołączył(a): 05 sty 2015
Posty: 393
Lokalizacja: Mielec
Pomógł: 14

podziel float na dwa inty przed przecinkiem jeden int i drugi int liczba po przecinku



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 19 paź 2018, o 16:23 
Offline
Nowy

Dołączył(a): 17 paź 2018
Posty: 13
Pomógł: 0

@Szofer
Jak mam podzielić?

Korzystając z:
Składnia: [ Pobierz ] [ Ukryj ]
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.


Otrzymam:
LiczbaINT=16
temp=209, a powinno być 210- czyli przypuszczam, że jest problem z dokładnością przy operacjach na liczbach zmiennoprzecinkowych.



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 20 paź 2018, o 16:28 
Offline
Użytkownik

Dołączył(a): 05 sty 2015
Posty: 393
Lokalizacja: Mielec
Pomógł: 14

uży jak to mowi Mirekj miodulo % , albo przesunięć bitowych, prościej sie nie da.



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 22 paź 2018, o 08:09 
Offline
Nowy

Dołączył(a): 17 paź 2018
Posty: 13
Pomógł: 0

Dziękuję za pomoc.

Zrealizowałem co chciałem, poza błędem w części ułamkowej.


Czyli tak jak pisałem wyżej, program źle odczytuje mi wartość po przecinku.

Na przykładzie liczby 16.23

Jeżeli użyję funkcji modf, która zwraca wartość całkowitą i ułamkową, otrzymam:


zapis funkcji: DECI= modf(16.23, INT)*1000
DECI=229
INT=16

Ale jeżeli zrobię coś takiego
DECI= (16.23-16)*1000, to otrzymam..... DECI=229. W rzeczywistości przypuszczam, że DECI=0,22(9).

Być może jest problem z funkcją ITOA, która źle dzieli liczbę na znaki i stąd błąd na wyświetlaczu. Ale jak wpiszę do wyświetlenia liczbę 230 to wyświetla ją prawidłowo.

Co może być przyczyną takiego przekręcania wyniku?


Co do samego modulo.
Zrobiłem sobie rozbicie liczby na cyfry w excelu korzystając z funkcji MOD i niestety przy częściach ułamkowych zaczynają się problemy- tzn. funkcja pokazuję nieprawidłowe wartości.
Przypuszczam, że w C będzie podobny problem.



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 22 paź 2018, o 14:02 
Offline
Użytkownik

Dołączył(a): 07 cze 2016
Posty: 563
Pomógł: 143

rektim napisał(a):
jest problem z dokładnością przy operacjach na liczbach zmiennoprzecinkowych.

Problemem niekoniecznie jest float. Problem dotyczy raczej ogólnie liczb ułamkowych w pozycyjnych systemów liczbowych. Przykładowo w systemie dziesiętnym też można powiedzieć, że jest problem z dokładnością wyniku dzielenia 1 przez 3, bo ile byśmy cyfr nie użyli (oczywiście nie mówię tu o ułamku zwykłym), będzie on obarczony jakimś błędem, ponieważ jest to ułamek o rozwinięciu dziesiętnym nieskończonym. Za to przykładowo w systemie o podstawie 3 (trójkowym) zapis będzie bardzo prosty, czyli 0.1

Podobnie jest w przypadku konwersji pomiędzy systemami liczbowymi (w Twoim przypadku z dziesiętnego na dwójkowy), bo nie każdy ułamek skończony w jednym systemie będzie również skończony w innym systemie. W przypadku kompilatora avr-gcc zarówno float jak i double są 32-bitowe, więc tylko taką precyzją dysponujemy, choć to w tym przypadku nie ma większego znaczenia. Bardziej chodzi o to, że liczba 16.23 z Twojego przykładu jest w systemie dwójkowym ułamkiem nieskończonym. Najbliższą reprezentacją liczby 16.23 (przy założeniu 32-bitowej precyzji) będzie liczba 16.229999542236328125, resztą z dzielenia przez 16 będzie 0.229999542236328125, pomnożone przez 1000 to będzie 229.999542236328125. Konwersja do int (bo takiego typu argumentu oczekuje funkcja itoa() ) nie zaokrągla wyniku, tylko obcina jego część ułamkową, w efekcie czego otrzymujesz 229

W programie również używasz skończonej precyzji, która (przynajmniej w momencie wyświetlania) zwykle nie przekracza 4 do 6 cyfr, przyjmijmy że w Twoim przypadku 4. Wystarczy więc podczas przygotowania do wyświetlenia części ułamkowej zaokrąglić wynik do odpowiedniej ilości cyfr, przykładowo modyfikując Twój sposób obliczeń:
Składnia: [ Pobierz ] [ Ukryj ]
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.

Oczywiście można to zrobić na różne sposoby, pokazałem jak to zrobić sposobem którego użyłeś, żeby łatwiej było Ci zrozumieć sens (funkcja fabs() została użyta, aby uzyskać prawidłowy wynik dla liczb ujemnych).
EDIT:
    Ta metoda ma niestety taką wadę, że nie zadziała prawidłowo dla liczb o części całkowitej równej zero. Należałoby taką sytuację uwzględnić w kodzie i zmienić sposób obliczeń. Wspomniana poniżej (przez kolegę dziobak7) funkcja sprintf() na pewno będzie wygodniejsza w użyciu. Ja tutaj raczej tylko chciałem wytłumaczyć skąd się bierze ta "niedokładność" liczb zmiennoprzecinkowych i że jakimś rozwiązaniem może być zaokrąglanie wartości. Jeśli wydajność kodu i zajętość pamięci nie jest problemem, to na pewno lepiej jest skorzystać z gotowych funkcji z biblioteki standardowej, jak wspomniana funkcja sprintf(). Jeśli zależy nam na wydajności i ograniczenie użytych zasobów, lepiej zrobić tak, jak wspomniałem poniżej, czyli wykonywać obliczenia na liczbach całkowitych. Wprawdzie nie zawsze da się taką metodę zastosować, ale w większości przypadków jest wystarczająca i najbardziej optymalna dla mikrokontrolerów ośmiobitowych bez FPU.
ENDEDIT.

No i tak, jak napisał kolega wyżej, stosowanie arytmetyki zmiennoprzecinkowej w 8-bitowych mikrokontrolerach AVR nie posiadających sprzętowego wsparcia dla operacji na tych liczbach jest niewskazane. Istnieją sposoby użycia zamiast tego obliczeń na liczbach całkowitych (bez utraty precyzji). Mirek na pewno nakręcił o tym (być może nie jeden) poradnik, ale ja niestety nie potrafię podać łącza (nie chce mi się szukać), a opisywanie tutaj tego po raz kolejny mija się z sensem.



Ostatnio edytowano 22 paź 2018, o 18:30 przez andrews, łącznie edytowano 1 raz

Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 22 paź 2018, o 21:15 
Offline
Uzytkownik zasłużony dla forum.atnel.pl
Avatar użytkownika

Dołączył(a): 16 lip 2012
Posty: 2088
Lokalizacja: Leżajsk / Kraków
Pomógł: 411

Jest jeszcze funkcja dtostrf double to C-string
Tutaj znajdziesz opis wielu funkcji dla avrów
Zastanów się też czy potrzebujesz liczby zmiennoprzecinkowej czy może wystarczy stałoprzecinkowa.

_________________
Dragonus Cracovus: Biomagia



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
Wyświetl posty nie starsze niż:  Sortuj wg  
Utwórz nowy wątek Odpowiedz w wątku  [ Posty: 12 ] 

Strefa czasowa: UTC + 1


Kto przegląda forum

Użytkownicy przeglądający ten dział: Brak zidentyfikowanych użytkowników i 7 gości


Nie możesz rozpoczynać nowych wątków
Nie możesz odpowiadać w wątkach
Nie możesz edytować swoich postów
Nie możesz usuwać swoich postów
Nie możesz dodawać załączników

Szukaj:
Skocz do:  
cron
Sitemap
Technologię dostarcza phpBB® Forum Software © phpBB Group phpBB3.PL
phpBB SEO