= Operacje zmiennoprzecinkowe w asemblerze =
== Wstęp ==
Procesory x86 zawierają koprocesor matematyczny do wykonywania operacji
zmiennoprzecinkowych.
Operacje zmiennoprzecinkowe są wykonywane za pomocą oddzielnego zestawu
instrukcji, kiedyś te instrukcje były wykonywane w ogóle przez inny
procesor.
Do operacji zmiennoprzecinkowych używany jest stos rejestrów
zmiennoprzecinkowych ST0 do ST7, gdzie ST0 jest szczytem stosu.
Wszystkie instrukcje zmiennoprzecinkowe operują na rejestrze ST0 i innym
rejestrze STx lub pamięci (wartości w pamięci muszą mieć odpowiedni
przedrostek podający rozmiar argumentu - TWORD dla 80-bitowych, QWORD dla
64-bitowych). Niektóre instrukcje mogą też wykonywać działania na liczbie
zmiennoprzecinkowej i całkowitej (np. FIMUL).

Wartości zmiennoprzecinkowe przechowywane w rejestrach mogą być 32-bitowe,
64-bitowe lub 80-bitowe, zależnie od precyzji. Format zmiennoprzecinkowy to
wykładnik i mantysa. Generalnie lepiej nie tworzyć tych wartości na własną
rękę, tylko zostawić to kompilatorowi/asemblerowi.

== Deklarowanie stałych zmiennoprzecinkowych w NASM ==
Stałe zmiennoprzecinkowe można podać jako argumenty dla pseudoinstrukcji
DD (32-bitowe), DQ (64-bitowe) i DT (80-bitowe). 

Wartości zmiennoprzecinkowe są tworzone, kiedy stała zawiera kropkę, np.
dd 1.0		; to jest coś zupełnie innego niż "dd 1"!
dq 3.141

Uwaga! Oczywiście podana wartość może być zaokrąglona zgodnie z precyzją
liczby zmiennoprzecinkowych.

Można też stosować zapis naukowy (wartość i wykładnik potęgi 10):
dd 12.e-3	; 0.012

== Przydatne instrukcje ==

FLD adres - wstawia zawartość pamięci na stos zmiennoprzecinkowy

FLD1 - wstawia liczbę jeden na szczyt stosu
FLDL2T - wstawia na stos liczbę log2(10)
FLDPI - wstawia na stos liczbę pi 
FLDZ  - wstawia na stos zero

FST adres - zapisuje zawartość ST0 do pamięci
FSTP adres - zapisuje zawartość ST0 do pamięci i zdejmuje ze stosu

FXCH STx, STy - zamienia dwa elementy stosu

FIMUL - mnoży ST0 przez liczbę całkowitą 32 lub 64-bitową w pamięci

FMUL adres - mnoży ST0 przez liczbę zmiennoprzecinkową w pamięci
FMUL STx - mnoży ST0 przez rejestr STx i zapisuje wynik w ST0
FMUL TO STx - mnoży ST0 przez STx i zapisuje wynik w STx
FMULP STx - mnoży ST0 przez STx, zapisuje wynik w STx i zdejmuje ST0 ze
	stosu

FDIV - podobnie jak FMUL, ale uwaga na kolejność argumentów!
FDIVR - FDIV z odwróconą kolejnością argumentów

FADD/FSUB - dodawanie/odejmowanie
FIADD/FISUB - dodawanie/odejmowanie liczb całkowitych

FCHS - zmiana znaku liczby w ST0
FABS - obliczenie wartości absolutnej ST0

Zaawansowane operacje matematyczne:
F2XM1 - oblicza (2^ST0)-1
FCOS - oblicza kosinus ST0
FSIN - oblicza sinus ST0
FSINCOS - oblicza sinus i kosinus, i wstawia sinus na stos w ST0, a kosinus
	w ST1
FPTAN - wylicza tangens ST0
FPATAN - wylicza arkus tangens ST1 podzielonego przez ST0
FSQRT - oblicza pierwiastek liczby w ST0
FYL2X - oblicza ST1*log2(ST0)

Są również porównania, warunkowe kopiowanie, konwersje na/z liczb
całkowitych, itd.

== Przekazywanie parametrów zmiennoprzecinkowych z C ==
Parametry zmiennoprzecinkowe są przekazywane w konwencji C na stosie, tak
jak pozostałe parametry (oczywiście o odpowiednim rozmiarze, stosownie do
typu).

== Zwracanie wyników zmiennoprzecinkowych do C ==
Zmiennoprzecinkowy wynik funkcji w konwencji C jest zwracany na szczycie
stosu zmiennoprzecinkowego (w rejestrze ST0).

Uwaga: To jest bardzo pobieżny przegląd operacji zmiennoprzecinkowych, do
właściwego użycia koprocesora należy zrobić obsługę wyjątków (np. przepełnień,
NaN - Not a Number), błędów zaokrągleń, itp. 

Literatura:
- Dokumentacja NASM
- http://docs.sun.com/app/docs/doc/817-5477/6mkuavhrj?a=view
- http://en.wikibooks.org/wiki/Floating_Point
- http://download.intel.com/design/PentiumII/manuals/24319102.PDF

Zadania:
- Napisać program wyliczający wartość funkcji kwadratowej ax^2+bx+c dla
wczytanych ze standardowego wejścia a, b, c i x.
- Napisać program wypisujący wartości sinusa i kosinusa w zakresie od -2pi
do 2pi co zadany krok.
- Napisać program znajdujący pierwsze miejsce zerowe funkcji (1/x)*sinx
metodą bisekcji.
- Napisać program wyliczający k pierwszych kroków ciągu (1+1/n)^n, gdzie k 
jest wczytywane ze standardowego wejścia.
