LABORATORIUM „PROCESORY SYGNAŁOWE W AUTOMATYCE PRZEMYSŁOWEJ” Zasady arytmetyki stałoprzecinkowej oraz operacji arytmetycznych w formatach Q 1. Zasady arytmetyki stałoprzecinkowej. Kody stałopozycyjne mają ustalone miejsce rozdziału części całkowitej i ułamkowej, czyli miejsce przecinka, co oznacza, że dokładność reprezentacji jest stała. Aby mówić o arytmetyce stałoprzecinkowej trzeba wiedzieć, w jaki sposób zapisywane są liczby dodatnie i ujemne. Dla reprezentacji liczb dodatnich i ujemnych najpowszechniej stosowane są dwa kody: - kod znak – moduł (ZM) - kod uzupełnienia do dwóch (U2) Kod ZM jest tworzony przez dodanie bitu znaku na początku każdej liczby, który wskazuje czy liczba jest dodatnia czy ujemna. Przyjęło się, że gdy liczba jest ujemna bit jest równy 1 a dalsze bity reprezentują moduł liczby. Gdy liczba jest dodatnia to bit znaku jest równy 0. Zakres reprezentowanych liczb zależy od długości słowa. Za pomocą n-bitowego słowa można przedstawić liczby z zakresu: 2 n 1 1 ; 2 n1 1 , gdzie n – ilość bitów liczby. Na przykład za pomocą 8-bitowego słowa można przedstawić liczby z zakresu –127 do 127. Liczba 34 10 będzie zapisana w tym kodzie jako 00100010, a liczba 34 10 jako 10100010. Kod ZM ma wadę która stwarza problemy przy realizacji algorytmów arytmetycznych, jest to podwójna reprezentacja liczby zero. Dla słowa 8-bitowego jest to liczba 00000000, jak i 10000000. Aby mówić o kodzie U2 należy najpierw wspomnieć o kodzie uzupełnienia do jednego (U1). W kodzie tym waga najbardziej znaczącej pozycji (MSB) ma wagę ujemną równą sumie wszystkich innych wag. Wartość liczbową można obliczyć ze wzoru: n 2 X a n1 2 n1 1 ai 2i , gdzie n – ilość bitów liczby, a – wartość bitu (0 lub 1) i 0 Stąd wynika, że w tym kodzie liczby dodatnie są reprezentowane tak jak w naturalnym kodzie binarnym (NKB), pod warunkiem, że długość słowa będzie odpowiednio duża, aby na MSB było „0”. Przykładowo liczba 4 10 nie może być reprezentowana przez 3-bitowe słowo 100, ale, przez co najmniej 4-bitowe 0100. Natomiast liczby ujemne na MSB mają „1”, a pozostałe bity mają wartości przeciwne niż bity słowa kodu NKB reprezentującego moduł tej liczby. Przykładowo liczba 34 10 jest przedstawiana w kodzie U1 na 8 pozycjach jako 00100010, a liczba 34 10 jako 11011101. Dla kodu U2 wartość liczbową można obliczyć ze wzoru: n 2 X a n1 2 n 1 a i 2 i , gdzie n – ilość bitów liczby, a – wartość bitu (0 lub 1). i 0 Stąd wynika, że w tym kodzie liczby dodatnie są reprezentowane tak jak w NKB, gdyż waga najbardziej znaczącej pozycji jest ujemna. Aby zapisać liczbę ujemną w kodzie U2 należy najpierw zapisać ją w kodzie U1 a następnie dodać 1. Na przykład 34 10 jest przedstawiana w kodzie U2 na 8 pozycjach jako 11011110. Istotną cechą kodu U2 jest fakt, że liczba 0 ma tylko jedną reprezentację (dla słowa 8bitowego 00000000). Wielką zaletą jest to, że podczas wykonywania operacji arytmetycznych wymagany jest tylko jeden sumator dla liczb dodatnich i ujemnych. Stałoprzecinkowe urządzenia DSP wykorzystują kod U2 i dlatego zasady arytmetyki stałoprzecinkowej zostaną omówione w oparciu o ten kod. Dodawanie liczb stałopozycyjnych. Operację dodawania realizuje się od najmniej znaczących bitów składników sumy: 34 10 1310 00100010 U 2 47 10 00001101U 2 00101111U 2 Odejmowanie liczb stałopozycyjnych. Operacja ta sprowadza się do dodawania liczb ujemnych: 34 10 1310 2110 00100010 U 2 11110011U 2 00010101U 2 Projektując układy realizujące operacje arytmetyczne należy uwzględniać zakres argumentów tych operacji oraz zakres wyniku. Ponieważ często zakłada się, że wynik operacji ma taką samą długość, co argumenty, to w czasie wykonywania operacji arytmetycznych należy kontrolować zakres wyniku. Innymi słowy mówiąc dodając liczby tego samego znaku, istnieje możliwość, że ilość bitów wyniku będzie większa niż ilość bitów argumentów. W takim przypadku wynik oczywiście jest błędny. Aby wykryć taką sytuację należy porównać znak argumentów ze znakiem wyniku. Mnożenie liczb stałopozycyjnych. Podobnie jak w systemie dziesiętnym tak i w systemie dwójkowym liczby mnoży się w tylu krokach z ilu bitów składają się czynniki. Jeśli mnożymy dwie liczby 8-bitowe w systemie dwójkowym, to mnożenie wykonujemy w 8 krokach a wynik może być 16-bitowy. Mnożenie liczb dziesiętnych polega na tym, że w jednym kroku mnożymy jedną cyfrę mnożnika przez mnożną, a iloczyn, zwany cząstkowym, wpisujemy z odpowiednim przesunięciem. Na końcu algorytmu sumujemy wszystkie iloczyny cząstkowe, co daje nam wynik. Ponieważ w urządzeniach cyfrowych stosuje się zwykle sumatory 2-argumentowe, to algorytm mnożenia musi być tak zmodyfikowany, aby w każdym kroku wykonywać sumowanie iloczynów cząstkowych. Dlatego w każdym kroku mnożenia liczb dwójkowych wykonywane są dwie operacje: dodawanie i przesunięcie iloczynu cząstkowego o jedną pozycję w prawo. Jednym ze składników dodawania jest zawsze iloczyn cząstkowy a drugi składnik zależy od aktualnej wartości najmniej znaczącego bitu (LSB) mnożnika. Jeśli jest on równy „1” to składnikiem jest mnożna, jeśli jest on równy „0” to składnikiem jest zero. Algorytm mnożenia można przedstawić następująco: 1.Wpisać na mniej znaczącej części (RL) rejestru mnożnik. 2.Do bardziej znaczącej części (RH) rejestru dodawać odpowiednią wartość (zero lub mnożną) w zależności od LSB. 3.Przesunąć wynik w rejestrze o jedną pozycję w prawo. 4.Jeśli wykonano odpowiednią liczbę kroków (liczba bitów argumentów) to algorytm sprawdza czy mnożnik był liczbą ujemną. Jeśli tak, należy dokonać korekcji, która polega na dodaniu do bardziej znaczącej części rejestru mnożną. Jeśli nie, korekcja nie jest wymagana i algorytm kończy się. Schemat blokowy algorytmu mnożenia: S TA R T N - licznik kroków M - m nożna R L - m nożnik RH - 00..00 N T R 0=1 R H =R H +0 R H =R H +M Przesunięcie R w prawo N =N -1 N T N =0 N M>0 R H =R H +M S T OP T Przykład: mnożenie liczb 0111 ( 7 10 ) i 0101 ( 510 ). 00000101 01110101 zapisanie mnożnika na mniej znaczącą część rejestru dodanie 7 krok 00111010 przesunięcie 1 00111010 dodanie 0 krok 00011101 przesunięcie 2 10001101 dodanie 7 krok 01000110 przesunięcie 3 01000110 dodanie 0 0010001 wynik 3510 przesunięcie krok 4 Istnieje możliwość przyspieszenia działania algorytmu przez grupowanie bitów. Przyspieszenie polega na tym, że w niektórych krokach algorytmu pomija się operację dodawania. W każdym kroku algorytmu modyfikacja zawartości RH następuje w zależności od pary najmniej znaczących bitów rejestru wyniku częściowego. Jeśli para ta jest 00 lub 11, to w danym kroku do RH dodaje się 0. Jeśli para ta jest 01, to w danym kroku do RH dodaje się mnożną, a gdy para ta jest 10, to od RH odejmuje się mnożną. Tak zmodyfikowany algorytm nosi nazwę algorytmu Bootha. Schemat blokowy algorytmu: STAR T N - licznik kroków M - m nożna RL - m nożnik RH - 00..00 R 1R 0 01 10 00 R H=RH +M 11 R H=RH +0 R H=RH -M Przesunięcie w prawo R N =N -1 N N =0 T S TOP Dzielenie liczb stałopozycyjnych. Dzielenie liczb dwójkowych jest działaniem trudniejszym od ich mnożenia, gdyż iloraz trzeba zapisać na skończonej liczbie bitów. Oznacza to, że wynik otrzymamy z pewną dokładnością. W algorytmie należy założyć liczbę kroków i długość wyniku. Algorytmów dzielenia jest bardzo dużo, a tu zostanie przedstawiony jeden z prostszych: 1.Wpisać do rejestru (RH+RL) dzielną. 2.Przesunąć zawartość rejestru o jedną pozycję w lewo. 3.Odjąć od zawartości RH dzielnik a) Jeśli wynik jest dodatni to na LSB rejestru RL wpisujemy 1, a w rejestrze RH pozostaje otrzymana różnica. b)Jeśli wynik jest ujemny to na LSB rejestru RL wpisujemy 0, a do rejestru RH zapisujemy wartość sprzed odejmowania. 4.Jeżeli wykonano założoną liczbę kroków algorytm kończy się, iloraz jest dostępny w RL a reszta w RH. Schemat blokowy: S TA R T N - licznik kroków M - dzielnik R L+R H - dzielna Przesunięcie R w lewo R H=RH -M T R H>0 N R 0 =0 RH=RH+M R 0 =1 N =N -1 N N =0 T S TOP Przykład: dzielenie liczb 00100100 36 10 - dzielna i 0101 510 - dzielnik. 00100100 zapisanie dzielnej w rejestrze R 0100100_ przesunięcie krok 1111100_ < 0 odejmowanie 1 01001000 R0=0, RH=RH+D 1001000_ przesunięcie krok 0100000_ > 0 odejmowanie 2 01000001 R0=1 1000001_ przesunięcie krok 0011001_ > 0 odejmowanie 3 00110011 R0=1 0110011_ przesunięcie 0001011_ > 0 odejmowanie 00010111 wynik 7 reszty 1 krok 4 R0=1 2. Zasady operacji arytmetycznych w formatach Q. Opisany wyżej format U2 nie zawiera ułamka binarnego i nie może reprezentować postaci ułamkowej liczby. Technika cyfrowego przetwarzania sygnałów bardzo często wykorzystuje jednak zapis ułamkowy. Jednym z powodów jest fakt, że podczas mnożenia ułamków wynik zawsze będzie mniejszy od jedności, dzięki czemu nie może nastąpić przepełnienie. W celu reprezentacji liczb ułamkowych niezbędne jest zastosowanie przecinka binarnego. Umiejscowienie przecinka nie ma wpływu na funkcjonowanie jednostki arytmetycznej, czy też układu mnożącego. Przecinek ten ma jedynie wpływ na dokładność wyniku i jest on kwestią umowną programisty. W celu ujednolicenia 16-bitowej struktury rodziny procesorów TMS320 firma Texas Instruments przyjęła format zapisu Q15. Liczba występująca po Q oznacza liczbę bitów części ułamkowej. Wynika z tego, że dla słowa 16-bitowego format Q15 wydziela 1 bit dla znaku liczby i 15 bitów na jej część ułamkową, bez przydziału bitów na część całkowitą. Podobnie liczba 4-bitowa o formacie Q3 zawiera 1 bit znaku i 3 bity części ułamkowej. Zasada tworzenia liczb w formacie Q polega na tym, że pierwszy bit określa znak liczby („0”-dodatnia, „1”- ujemna), kolejne bity określają wartość ułamka. N 1 Wartość tą można obliczyć ze wzoru: X a0 a n 2 n , a0 - najstarszy bit, określa znak n 1 liczby, N - ilość bitów liczby. Przykład: Liczba w formacie Q3 0.101 jest dwójkowym odpowiednikiem dziesiętnego ułamka 0,625. Liczba w formacie Q3 1.110 jest dwójkowym odpowiednikiem dziesiętnego ułamka -0,75. Wszystkie operacje arytmetyczne na liczbach, niezależnie od formatu Q, w jakim są zapisane, realizuje się w jednakowy sposób, dlatego wszystkie przykładowe obliczenia zostaną przeprowadzone w formacie Q3. Dodawanie i odejmowanie liczb w formacie Q3. Zasady dodawania i odejmowania są identyczne jak w przypadku binarnych liczb całkowitych, co można zauważyć w przykładach: 0,750 10 0,12510 0,87510 0 .110U 2 0.001U 2 0 .111U 2 0,750 10 0,12510 0,625 10 Mnożenie liczb w formacie Q3. Przykład: mnożenie liczb 0.100 ( 0,510 ) i 0.011 ( 0,37510 ). 00000100 00000100 zapisanie mnożnika na mniej znaczącą część rejestru dodanie 0 krok 00000010 przesunięcie 1 00000010 dodanie 0 krok 00000001 przesunięcie 2 00110001 dodanie 0,375 krok 00011000 przesunięcie 3 00011000 dodanie 0 00.001100 wynik 0,187510 przesunięcie krok 4 0 .110 U 2 1.111U 2 0 .101U 2 Użycie postaci ułamkowej powoduje, że mnożenie nigdy nie wywoła przepełnienia, natomiast kolejne dodawania mogą je spowodować. Rodzina układów TMS320, jest wyposażona w mechanizm zabezpieczający przed negatywnymi skutkami przepełnienia oraz sygnalizuje jego wystąpienie.