ATNEL tech-forum
https://forum.atnel.pl/

Tablica wartości funkcji utworzona preprocesorem
https://forum.atnel.pl/topic3419.html
Strona 1 z 1

Autor:  Krauser [ 29 cze 2013, o 17:50 ]
Tytuł:  Tablica wartości funkcji utworzona preprocesorem

Obrazek
Przeglądając sieć natrafiłem na fajny trik. Typowe podejście na tablicę wartości funkcji wygląda tak, że chcąc skorzystać z przykładowo sinusa, dołączamy do programu kod np. z tej strony albo sami obliczamy to w arkuszu kalkulacyjnym i przenosimy łatwiej lub trudniej do kodu programu. Można to zrobić też jak pokazano poniżej:
Plik main.c:
Składnia: [ Pobierz ] [ Ukryj ]
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.

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


Jeśli tak jak w przykładzie potrzeba 24 wartości sinusa to w pliku values.txt 24 razy powtarza się dokładnie tą samą linię. Parametr __LINE__ zwraca numer linii (tutaj 1-24). Jako, że zaczyna się numeracja od 1 to we wzorze na sinus odejmowana jest najpierw 1 i wtedy argument ma wartość 0-23. Przeliczając to na stopnie mnoży się razy krok czyli 15, bo akurat potrzeba 24 wartości z całego zakresu 0-360 stopni. Następnie konieczna jest zamiana stopni na radiany (/180.0*M_PI) dlatego, że funkcja sinus na takich wartościach operuje. Kolejnym krokiem jest dopasowanie wyniku do wartości 0-255 co jest realizowane poprzez pomnożenie razy 128 i dodanie 127. No i już nie potrzeba korzystać z innych programów :)

Autor:  mirekk36 [ 29 cze 2013, o 18:56 ]
Tytuł:  Re: Tablica wartości funkcji utworzona preprocesorem

O matko ;) jak pierwszy raz to przeczytałem i zobaczyłem to - powiedziałem tylko hyyyyy i nic nie zrozumiałem ;) .... więc jeszcze raz, i jeszcze raz .... i jeszcze raz .... i tak jeszcze n razy jak w tej tabeli ;)

a jak zaskoczyłem ;) .... hahahaha - no mega super trick - ale popraw mnie jeśli się mylę bo może jednak coś na końcu przeoczyłem

rezultatem tego myku jest fakt że, tzn postaram się to podsumować tak na mój rozum:

1. w programie nie zostaną użyte funkcje zmiennoprzecinkowe z math.h ;)
2. w programie zostanie stworzona ładna tablica sinusów w pamięci FLASH
3. a wartości tej tablicy przygotuje grzecznie sługa PREPROCESOR ;)
4. plik values.txt jest tylko taki pomocniczy .... ;) żeby zadać fuchę preprockowi ;)

dobrze myślę ?

jeśli tak to działa to na prawdę Krauser super mega TRICK obczaiłeś w necie ! ;) gratulacje

no i super że się nim podzieliłeś

Autor:  SunRiver [ 29 cze 2013, o 18:58 ]
Tytuł:  Re: Tablica wartości funkcji utworzona preprocesorem

Ano właśnie ... kiedyś to widziałem i gdzieś przepadło w przepastnych czeluściach sieci zaiste .
dzięki za przypomnienie , bo robienie na piechotę czasem dobija :)

Autor:  jachu [ 29 cze 2013, o 19:58 ]
Tytuł:  Re: Tablica wartości funkcji utworzona preprocesorem

genialne :)

Autor:  chodzikman [ 29 cze 2013, o 20:29 ]
Tytuł:  Re: Tablica wartości funkcji utworzona preprocesorem

Ja ostatnio spotykając się z tym problemem, mając naprawdę mało czasu napisałem sobie po prostu programik który generował kod.
Generuje on sinusy o 6 różnych amplitudach w dwuwymiarowej tablicy i nie ma problemu z wygenerowaniem za pomoca tego kodu innych funkcji z math.c po lekkim przerobieniu, treść jego jest taka:

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


Pod linuksem odpalam skompilowany program np.
Kod:
./sinus_gen > sinus.h

więc nie potrzebuje zapisu do pliku, ale pod windowsem mogłoby się to przydać.

Ponieważ miałem problemy z przetwornikiem, dodatkowo zrobiłem opcję generowania przebiegu do matlaba, aby porównać sobie tablicę do tego, co widze na oscyloskopie.

Wykorzystanie preprocesora napewno jest bardziej "hackerskie", ale i trudniejsze w zrozumieniu (chociaż mnie strasznie podobają się takie tricki :) )

Autor:  krz [ 29 cze 2013, o 22:22 ]
Tytuł:  Re: Tablica wartości funkcji utworzona preprocesorem

@mirekk36
Te wartości nie znajdą się tam w magiczny sposób, bez wywołania funkcji sin(x) z biblioteki math.
Mniej więcej będzie to wyglądać tak:
1. Preprocesor wpierw zamieni __LINE__ w pliku values.txt na odpowiadające im numery linii
2. Następnie w miejsce #include "values.txt" wklei zawartość tego pliku czyli:
Kod:
const uint8_t sin_tab[TAB_SIZE] PROGMEM ={
    VALUE(1),
    VALUE(2),
    ...,
    VALUE(24),
};

2. Wszystkie miejsca gdzie użyte jest makro VALUE(a) przed kompilacją zamieni na:
Kod:
const uint8_t sin_tab[TAB_SIZE] PROGMEM ={
    (sin( ( ( (1-1) * STEP )/180.0 )*M_PI )*128 + 127 ),
    (sin( ( ( (2-1) * STEP )/180.0 )*M_PI )*128 + 127 ),
    ...,
    (sin( ( ( (24-1) * STEP )/180.0 )*M_PI )*128 + 127 ),
};

3. Kompilator wygeneruje kod w asemblerze, który inicjalizuje tę tablicę, czyli do każdej wartości z tablicy przypisze wartość otrzymaną po wywołaniu tego wyrażenia.

Tak przy okazji wydaje mi się, że ten wzór na zamianę <-1.0f, 1.0f> na <0, 255> jest zły.
Jak sin(x) wyjdzie -1 to otrzymasz (-1.0f)*128 + 127 => -128.0f + 127 => -1.0f i po rzutowaniu na unsigned short int wyjdzie 255.
Imo lepiej użyć wzoru:
Kod:
(sin((a-1)*STEP*PI/180.0f)*127.5f + 127.5f)


Wg mnie zamiast kombinować z takimi hackami lepiej jest po prostu wygenerować sobię tę tablicę i ręczne przekleić do kodu. Niestety takie stuczki zmniejszają czytelność i jak nie znamy dokładnego zachowania kompilatora to mogą prowadzić do powstania błędów w programie.

Autor:  mirekk36 [ 29 cze 2013, o 23:46 ]
Tytuł:  Re: Tablica wartości funkcji utworzona preprocesorem

krz napisał(a):
Te wartości nie znajdą się tam w magiczny sposób, bez wywołania funkcji sin(x) z biblioteki math


Nie pisałem, że magiczny ;) pisałem że w programie nie zostanie użyta biblioteka math.h - i nie zostanie bo całe wyliczenia zostaną zrobione na etapie preprocesora właśnie i to jest fajne.

Dobrze, że rozpisałeś to po swojemu w punktach bo dzięki temu jeszcze łatwiej będzie zrozumieć ideę działania tego tricku wielu ludziom ;)

krz napisał(a):
Wg mnie zamiast kombinować z takimi hackami lepiej jest po prostu wygenerować sobię tę tablicę i ręczne przekleić do kodu


łeeeej ;) no bez przesady - po to są właśnie takie sposoby, jako alternatywa i tak należy to rozumieć. Sposób działa i to się liczy - jak się już go zrozumie - to okazuje się że wcale nie jest skomplikowany a wręcz banalnie prosty - i to jest siła takich rozwiązań w niektórych przypadkach.

krz napisał(a):
Niestety takie stuczki zmniejszają czytelność i jak nie znamy dokładnego zachowania kompilatora to mogą prowadzić do powstania błędów w programie


To by oznaczało, że w zasadzie jak coś wygląda dziwnie - to lepiej tego nie ruszać. To jest dla osób które już zaskoczą o co tu chodzi - a myślę że sporo zaskoczy dzięki temu całemu wątkowi ... i nic nie będzie się działo ze zmniejszeniem czytelności kodu ;) ... tym bardziej, że działa to TYLKO na poziomie preprocesora. Dlatego ja akurat uważam, że warto na pewno czasem to wykorzystywać ;) jak najbardziej.

Autor:  Krauser [ 30 cze 2013, o 11:15 ]
Tytuł:  Re: Tablica wartości funkcji utworzona preprocesorem

krz napisał(a):
Tak przy okazji wydaje mi się, że ten wzór na zamianę <-1.0f, 1.0f> na <0, 255> jest zły.
Jak sin(x) wyjdzie -1 to otrzymasz (-1.0f)*128 + 127 => -128.0f + 127 => -1.0f i po rzutowaniu na unsigned short int wyjdzie 255.
Imo lepiej użyć wzoru:
Kod:
(sin((a-1)*STEP*PI/180.0f)*127.5f + 127.5f)

Tak wzór jest zły (pozdrawiam panią od matematyki :oops: ), ale w wyniku działań na liczbach zmiennoprzecinkowych sin(270) > -1 i po odcięciu części ułamkowej wychodzi 0. To osobny temat poruszony już przy okazji omawiania obliczania UBRR. W związku z tym lepiej użyć jeszcze innego wzoru (tylko dla preprocesora, gdzie wynik jest większy o 0,5):
Składnia: [ Pobierz ] [ Ukryj ]
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.

Teraz wartości są jak te z arkusza po zaokrągleniu. Dodanie do wzoru 360 nic nie zmienia, ale wtedy obie wartości dla 0 i 180 stopni są równe i wynoszą 128 (jak w arkuszu kalkulacyjnym). Chociaż z drugiej strony bardziej symetryczne wyniki są, gdy dla 180 mamy wartość 127. Co kto woli. Środek jest na poziomie 127,5, a takiej wartości nie można wybrać. Zwiększenie rozdzielczości do 16 bitów też nic nie zmieni, bo znowu środek jest na poziomie 511,5 .

Autor:  rafrew [ 15 wrz 2013, o 20:05 ]
Tytuł:  Re: Tablica wartości funkcji utworzona preprocesorem

Czy da się się w tym "tricku" podstawić inną funkcję zamiast sinusa z math.h? Konkretnie chodzi mi o funkcję przez siebie zdefiniowaną spoza biblioteki standardowej.?

Autor:  Krauser [ 15 wrz 2013, o 20:39 ]
Tytuł:  Re: Tablica wartości funkcji utworzona preprocesorem

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

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

Można używać innych makr (makro to nie funkcja, ale może ją zastąpić) np.
Składnia: [ Pobierz ] [ Ukryj ]
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.

Autor:  rafrew [ 15 wrz 2013, o 20:53 ]
Tytuł:  Re: Tablica wartości funkcji utworzona preprocesorem

Czy chcesz powiedzieć, że preprocesor umie policzyć wartość sinusa z liczby? Raczej nie. Zakomentowanie lini #include<math.h> spowoduje błędy, zatem wartość sinusa obliczana jest na podstawie algorytmu zawartego w bibliotece math.h.

Cytuj:
Zauważ, że:
Składnia: [ Pobierz ] [ Ukryj ]
język c

#define VALUE(a) (sin( ( ( (a-1) * STEP)/180.0 )*M_PI )*127.5 + 128 )/* wzór na wartość sinusa */

GeSHi

to nie jest po prostu:
Składnia: [ Pobierz ] [ Ukryj ]
język c

#define VALUE(a) (sin(a))


w sumie pierwsze sprowadza się do drugiego

Autor:  mirekk36 [ 15 wrz 2013, o 20:59 ]
Tytuł:  Re: Tablica wartości funkcji utworzona preprocesorem

rafrew napisał(a):
Czy chcesz powiedzieć, że preprocesor umie policzyć wartość sinusa z liczby?


Kolego naprawdę poczytaj troszkę o preporcesorze gdzieś ;) ... pewnie że preprocesor oblicza sin() i to bez żadnego inkludowania <math.h> bo ta biblioteka jest potrzebna tylko gdy obliczeń trzeba dokonywać w kodzie w procku.

Co to za problem dla preprocesora obliczyć sin czy podobną funkcję - na PC? miałby to być kłopot ?

a makro VALUE() działa tu TYLKO i wyłącznie w taki sposób że zwraca stałą dosłowną która zostanie wyliczona przez preprocesor właśnie

Autor:  rafrew [ 15 wrz 2013, o 21:25 ]
Tytuł:  Re: Tablica wartości funkcji utworzona preprocesorem

Ok, jeśli tak to już wszystko jasne. Faktycznie muszę coś poszukać bo o funkcjach jakie umie wyliczyć preprocesor jakoś nigdzie się nie natknąłem. Dzięki za odpowiedzi. Pozdrawiam.

Autor:  karolek [ 11 lut 2014, o 00:18 ]
Tytuł:  Re: Tablica wartości funkcji utworzona preprocesorem

Tamta stronka juz wygasła wiec pomyslalem ze moze dobrze bedzie zgrac z google webcache tametego generatora poki jeszcze jest dostepne.

Autor:  rskup [ 21 maja 2014, o 09:53 ]
Tytuł:  Re: Tablica wartości funkcji utworzona preprocesorem

Witam,

Właśnie natknąłem się na inny ciekawy sposób tworzenia tablicy z wartościami wyliczanymi przez preprocesor. Nie trzeba robić dodatkowego pliku do includowania a wykorzystać rekurencję:
Kod:
#define XTAB0(n) func(n),
#define XTAB1(n) XTAB0(n) XTAB0(n+1)  XTAB0(n+2)  XTAB0(n+3)
#define XTAB2(n) XTAB1(n) XTAB1(n+4)  XTAB1(n+8)  XTAB1(n+12)
#define XTAB3(n) XTAB2(n) XTAB2(n+16) XTAB2(n+32) XTAB2(n+48)
#define XTAB4(n) XTAB3(n) XTAB3(n+64) XTAB3(n+128) XTAB3(n+192)

const uint8_t TABLE[] PROGMEM = { XTAB4(0) };


Dla powyższego kodu dostajemy w TABLE[] wartości będące wynikiem func(n) dla n od 0 do 255. Ale można to bardzo łatwo zmodyfikować na inne wielkości tablic oraz zmienić wartość początkową n na inną (zmiana w wywołaniu XTAB4(start_value)).

--
Pozdrawiam,
Robert

Autor:  mirekk36 [ 21 maja 2014, o 10:04 ]
Tytuł:  Re: Tablica wartości funkcji utworzona preprocesorem

no fajne ciekawostki i smaczki ;)

Autor:  m@ciej [ 26 gru 2014, o 11:08 ]
Tytuł:  Re: Tablica wartości funkcji utworzona preprocesorem

A ja dłubałem program w Delphi, co mi zmienia format Excelowego słupka na format Pgm Space. Szlo to dość szybko, ale ta metoda jest niezła. Będę musiał ją przetrenować bo w perspektywie jest wpisanie okolo 30 tablic po 2048 elementów 16-bitowych by zrobić wavetable.
Jak będzie zainteresowanie, udostępnię wspomniany programik.

Strona 1 z 1 Strefa czasowa: UTC + 1
Powered by phpBB® Forum Software © phpBB Group
https://www.phpbb.com/