Sinus, cosinus

2008-04-08 16:18

Jeśli w praktyce obliczamy wartości funkcji sinus lub cosinus dla danego kąta, to bardzo często zdarza się, że tak naprawdę potrzebujemy ich obu. Jest tak przy obliczaniu punktów okręgu, przy rozkładzie wektorów sił i jeszcze dla wielu innych okoliczności. Zależy nam naturalnie, aby policzyć to wszystko tak szybko, jak tylko się da, dlatego dobrze jest stosować funkcje w rodzaju sincos, które wyznaczają obie wartości jednocześnie.

Niestety nie każdy język programowania taką funkcję posiada. Mają ją języki shaderowe (GLSL, HLSL i asembler GPU) oraz np. Delphi, ale już nasz ulubiony C++ nie. Można by oczywiście uzupełnić ten brak poprzez taką implementację:

  1. void sincos(float angle, float* sine, float* cosine)
  2.     { *sine = sin(angle); *cosine = cos(angle); }

ale chyba nie trzeba nikogo przekonywać, że większego sensu ona nie ma :) Nie występuje tu bowiem żaden zysk na wydajności, bo wartości są obliczane oddzielnie.

Co więc można zrobić? Ano wykorzystać to, co drzemie w jednostce zmiennoprzecinkowej procesora, ale nie jest używane przez wszystkie języki wyższego poziomu. Istnieje mianowicie instrukcja FSINCOS, która wykonuje całą potrzebną “magię”. Należy ją tylko opakować:

  1. void sincos(float angle, float* sine, float* cosine)
  2. {
  3.     __asm
  4.     {
  5.         mov eax, sine
  6.         mov edx, cosine
  7.        
  8.         fld     angle
  9.         fsincos
  10.         fstp    dword ptr [edx]
  11.         fstp    dword ptr [eax]
  12.     }
  13. }

Jakkolwiek tajemniczo to może wyglądać, funkcja ta po prostu ładuje argument (kąt) na stos FPU, by potem odebrać wyniki – cosinus i sinus. W przypadku operowania na liczbach typu float nie ma możliwości podania zbyt dużego/małego argumentu, więc nie trzeba sprawdzać rejestru flag.

I tyle – funkcja mała, acz użyteczna. Asembler czasem się przydaje, proszę państwa ;P

Tags: , ,
Author: Xion, posted under Programming »


13 comments for post “Sinus, cosinus”.
  1. q:
    April 9th, 2008 o 1:09

    a nie lepiej wrzucić sobie wynik funkcji do tablicy na początku programu i potem tylko pobierać przez jakieś makro?

  2. moriturius:
    April 9th, 2008 o 7:18

    @q: no jeśli wiesz dla jakiego konkretnie kąta będą Ci potrzebne te wartości to pewnie że łatwiej i szybciej, ale weź pod uwagę, że kąt może zmieniać się dynamicznie. Musiałbyś wtedy stworzyć całą tablicę wartości.

    Zresztą gdzieś już o tym pisałem, można stworzyć 2 tablice np 3600 elementów typu float i powpisywać do nich wartości sin i cos. Można też większe dla zwiększenia precyzji, ale to chyba nie jest najlepszy pomysł mimo wszystko ^^

    Ciekawe czy ten kod będzie działał pod g++ w linuxie…

  3. Queight:
    April 9th, 2008 o 11:23

    Xion: dzięki za kodzik, przyda się ;)

    moriturius: AFAIK nie będzie, bo GCC ma inną składnię “embeddowanego” asm’a.

  4. moriturius:
    April 9th, 2008 o 11:51

    @Queight: wiem juz wiem ^^. Wlasnie kombinuje jak to przepisac na GCC ;) Mam tylko problem z wywolaniami fstp i tym podobnych.

  5. agent_J:
    April 9th, 2008 o 15:43

    @moriturius: gcc i glibc już to mają :P

  6. Xion:
    April 9th, 2008 o 17:34

    q: Funkcja sincos() to optymalizacja z gatunku niewielkich, ale za to pewnych i bezproblemowych. Tablicowanie może dać większe zyski, ale i większe problemy, chociażby z dokładnością. Chyba w GPG2 jest ładnie napisane o tablicowaniu sinusów.

  7. moriturius:
    April 9th, 2008 o 22:08

    @agent_J: gdzie? ^^

  8. agent_J:
    April 9th, 2008 o 22:22

    http://linux.die.net/man/3/sincos

  9. moriturius:
    April 9th, 2008 o 23:21

    @agent_J: dzieki ^^ w sumie to moglem sie domyslic ze bedzie w math.h… ale ok – pozno juz :P

  10. ed:
    April 10th, 2008 o 0:33

    Tylko że teraz rozkaz fsincos jest trzymany tylko dla zachowania kompatybilności. Biblioteki Intela liczą to na SSE bo jest szybciej :)

  11. Xion:
    April 10th, 2008 o 17:26

    Ale za to FPU jest na większości nawet najbardziej archaicznych komputerów, które dotrwały do naszych czasów :)

  12. agent_J:
    April 11th, 2008 o 13:34

    Xion: których i tak nikt nie używa (nerdy się nie liczą ;))

Comments are disabled.
 


© 2017 Karol Kuczmarski "Xion". Layout by Urszulka. Powered by WordPress with QuickLaTeX.com.