Ustalona arytmetyka punktów na mikrokontrolerach

12

Często używamy mikrokontrolerów do robienia rzeczy w naszych robotach, ale musimy wykonać pewne obliczenia dziesiętne. Używanie zmiennych zmiennoprzecinkowych jest bardzo wolne, ponieważ programowa biblioteka zmiennoprzecinkowa jest automatycznie dołączana (chyba że masz wysokiej klasy mikrokontroler). Dlatego zazwyczaj używamy arytmetyki punktów stałych.

Ilekroć to robię, po prostu używam liczby całkowitej i pamiętam, gdzie jest miejsce dziesiętne. Jednak należy zadbać o to, aby wszystko było spójne, szczególnie gdy obliczenia obejmują zmienne, w których przecinek dziesiętny znajduje się w innym miejscu.

Zaimplementowałem funkcję atan2 o stałym punkcie, ale ponieważ próbowałem wycisnąć każdą ostatnią kroplę o ograniczonej precyzji (16 bitów), często zmieniałem definicję miejsca przecinka dziesiętnego i zmieniałbym się, gdy go poprawiałem. Ponadto miałbym pewne stałe, jako quasi-przeglądową tabelę, które same mają gdzieś sugerowaną kropkę dziesiętną.

Chcę wiedzieć, czy jest lepszy sposób. Czy istnieje biblioteka lub zestaw makr, które mogą uprościć stosowanie zmiennych stałoprzecinkowych, ułatwiając mnożenie i dzielenie między zmiennymi mieszanymi oraz pozwalając na deklarację liczb dziesiętnych lub wyrażeń stałych, ale automatycznie konwertując do pożądanej reprezentacji stałych punktów podczas kompilacji czas?

ronalchn
źródło
1
Myślę, że tak naprawdę jest to lepsze w przypadku przepełnienia stosu, ponieważ rozwiązanie jest dość ogólne i nie ma wiele wspólnego z robotyką.
Shahbaz
1
@Jakob - Pamiętaj, że oba te pytania zostały zamknięte, ponieważ nie były konstruktywne.
Mark Booth
1
Jest to coś, co uczyniłoby C ++ bardzo przydatnym dla systemów osadzonych. Szablony automatycznie generują poprawny i optymalny kod.
Rocketmagnet
1
Czy mogę zobaczyć twoją funkcję atan? W moich badaniach akademickich próbuję rozwiązać problem konwersji zmiennoprzecinkowej na punkt stały i chętnie bym się tym zajął.
Joe Hass,
1
@ronalchn Części Arduino (e mikro AVR) języka są zaimplementowane w C ++. Istnieje również biblioteka AVR C ++ . I ten wątek, w którym kompilatory mają być używane.
embedded.kyle

Odpowiedzi:

7

Byłoby miło, gdybyśmy mogli powiedzieć kompilatorowi zakres i precyzję każdej zmiennej wejściowej o stałym punkcie (być może żadna z dwóch nie ma punktu radix w tej samej lokalizacji), a automatycznie - w czasie kompilacji - używałby prawidłowego zakresu oraz operacje precyzji i zmiany skali dla wartości pośrednich i końcowych w szeregu obliczeń. Słyszałem pogłoski, że można to zrobić w języku programowania Ada lub w szablonach C ++.

Niestety, najbliższe, jakie widziałem, to biblioteki arytmetyczne o stałym punkcie, które wymagają od ciebie, programisty, ręcznego wyboru właściwej reprezentacji i ręcznego sprawdzenia, czy każda operacja zachowuje odpowiedni zasięg i precyzję. Czasami ułatwiają mnożenie i dzielenie między zmiennymi mieszanymi. Jak na przykład:

David Cary
źródło
Niemal na pewno jest to możliwe przy użyciu szablonów C ++.
Rocketmagnet
Właściwie pracuję nad czymś takim jak twój komentarz „byłoby miło, gdyby ...”. Jest to wtyczka dla gcc, która konwertuje zmiennoprzecinkowy kod C na stały, optymalizując wszystkie lokalizacje punktów binarnych po drodze. Mam artykuł przesłany do czasopisma ACM, a drugi w przygotowaniu. Jeśli masz kod C dla funkcji atan, chętnie go wypróbuję.
Joe Hass,
+1 za znacznie bardziej kompletną odpowiedź niż moja. Zredagowałem link w moim, aby zawierał link do miejsca, w którym należy poprosić o kod źródłowy, aby odpowiedzieć na komentarz Marka Bootha. Możesz także zaktualizować swój link. Zrobiłbym to sam, ale sugerowana edycja jest w kolejce i blokuje mnie.
embedded.kyle
1
@Rocketmagnet Z pewnością możliwe jest zaimplementowanie punktów stałych za pomocą szablonów, patrz FixedPoints (zrzeczenie się: Napisałem to, i nadal jest bardzo „młody”).
Pharap
link gcc „a” jest zepsuty
Lesto
2

Użyłem TI IQMath Biblioteka wdrożyć wirtualny zmiennoprzecinkowych na ich DSP stałoprzecinkowych.

Biblioteka Texas Instruments TMS320C28x IQmath to zbiór wysoce zoptymalizowanych i precyzyjnych funkcji matematycznych dla programistów C / C ++ w celu płynnego przeniesienia algorytmu zmiennoprzecinkowego do kodu stałoprzecinkowego na urządzeniach TMS320C28x. Procedury te są zwykle używane w aplikacjach intensywnie obliczeniowych w czasie rzeczywistym, w których kluczowa jest optymalna szybkość wykonywania i wysoka dokładność. Korzystając z tych procedur, można osiągnąć prędkości wykonywania znacznie szybciej niż równoważny kod napisany w standardowym języku ANSI C. Ponadto, dzięki gotowym do użycia funkcjom o wysokiej precyzji, biblioteka TI IQmath może znacznie skrócić czas opracowywania aplikacji DSP.

To wykorzystuje pewne rzeczy specyficzne dla TI, ale użyłem również tego kodu jako podstawy do implementacji wirtualnej matematyki zmiennoprzecinkowej na innych mikrokontrolerach. Przeniesienie zajmuje trochę pracy, ale jest o wiele łatwiejsze niż rozpoczęcie od zera.

embedded.kyle
źródło
@downvoter Chcesz skomentować, co było nie tak z moją odpowiedzią?
embedded.kyle
+1: Ta biblioteka jest lepsza niż to, czego używa teraz („po prostu użyj liczby całkowitej”). Nie robi wszystkiego, o co pierwotnie zadano pytanie, ale myślę, że taka odpowiedź (przydatna, ale nie kompletne rozwiązanie) nie zasługuje na głosowanie negatywne - chyba że faktycznie istnieje kompletne rozwiązanie (co wątpię w tym przypadku ).
David Cary
Wydaje mi się, że odpowiedź, która jest specyficzna dla jednego zakresu urządzeń i jest bezpłatna, jak w piwie, a nie w mowie, ma ograniczone zastosowanie dla przyszłych gości.
Mark Booth
@MarkBooth Zmieniłem łącze z biblioteki C28x na bibliotekę C64x. Jeśli skorzystasz z tego linku, możesz poprosić o kod źródłowy. Aby uzyskać dostęp, potrzebujesz firmowej lub uniwersyteckiej wiadomości e-mail. Wciąż za darmo jak w piwie i mowie. Musisz tylko podnieść rękę i poczekać na wezwanie, zanim będziesz mógł mówić. Trochę denerwujące, ale kiedy już masz kod źródłowy, można go dostosować do dowolnego procesora, który ci się podoba.
embedded.kyle
Dzięki kodowi źródłowemu Thanks @ embedded.kyle jest zdecydowanie lepszy niż tylko binarny, ale wciąż mało ogólnego użytku, jeśli licencja pozwala na używanie go w ograniczony sposób. Według strony C6x Software Libraries to źródło jest wydawane wyłącznie na licencji TI Commercial License , która prawie na pewno nie jest darmowa jak w mowie .
Mark Booth
1

Istnieje wiele implementacji (bez bibliotek, od razu jestem świadom) skalowania binarnego (inaczej skalowania B)

W ten sposób zapisujesz w pamięci (a nawet lepiej, dokumentujesz kod ...), gdzie znajduje się przecinek dziesiętny, używając przesunięć, aby przesunąć przecinek dziesiętny w górę lub w dół.

Użyłem skalowania B w asemblerze w projektach obronnych, nawet na najmniejszych procesorach, więc mogę ręczyć za jego przydatność do wszystkiego innego ...

Andrew
źródło
Prawdopodobnie coś takiego, ale nigdy nie widziałem, by to nazywało się skalowaniem b. Myślę o nim jako stałego punktu - dziesiętny nie pływa, bo mimo że punkt dziesiętny może się zmienić w trakcie obliczeń, każdy zawsze ma zmienny przecinek stałe w określonym miejscu
ronalchn
0

W przypadku korzystania z całkowitą pamiętać gdzie „punkt” jest, są one rodzajem użyciu arytmetyki zmiennoprzecinkowej. Punkt stały, naprawdę ma punkt stały .

atancosπ-π

Zależy to od zakresu wartości, których potrzebuje twoja aplikacja, ale możesz chcieć całkowicie przejść do reprezentacji punktu stałego. To jest, na przykład, zamiast utrzymywania takiej liczby:

struct num
{
    uint16_t number;
    uint16_t decimal_point;
};

gdzie numberjest liczba całkowita i decimal_pointmówi, gdzie jest przecinek dziesiętny, możesz zapisać go w następujący sposób:

struct num
{
    uint16_t integer;
    uint16_t fraction;
};

gdzie jest liczba całkowita integer.fraction, która ma to samo użycie pamięci, wyższy zakres wartości i ogólnie jest prostsza w użyciu.

Shahbaz
źródło
Właściwie zapisanie kropki dziesiętnej sprawia, że ​​bardziej przypomina ona liczbę zmiennoprzecinkową. Zwykle kropka dziesiętna jest definiowana w czasie kompilacji i zmieniasz między reprezentacjami w zależności od operacji.
Jakob
Nie mam na myśli zapamiętywania zapisanego w zmiennej, mam na myśli zapamiętywanie, ponieważ pamiętam, jak interpretować wynik (wiedząc, gdzie jest przecinek dziesiętny)
ronalchn
@ronalchn, rozumiem. Miałeś na myśli coś z #define, prawda? Myślałem, że faktycznie go przechowujesz i może się różnić w zależności od tego, jak duży lub mały jest twój numer.
Shahbaz
@ronalchn - czy myślisz o skalowaniu B? (patrz moja odpowiedź)
Andrew