Podnormalny numer

Niepowiększony system zmiennoprzecinkowy zawierałby tylko liczby znormalizowane (zaznaczone na czerwono). Zezwolenie na liczby zdenormalizowane (kolor niebieski) rozszerza zasięg systemu.

W informatyce liczby podnormalne są podzbiorem liczb zdenormalizowanych (czasami nazywanych denormalnymi ) , które wypełniają lukę niedomiaru wokół zera w arytmetyce zmiennoprzecinkowej . Każda liczba różna od zera, której wielkość jest mniejsza od najmniejszej liczby normalnej, jest podnormalna .

Uwaga dotycząca użycia: w niektórych starszych dokumentach (zwłaszcza dokumentach norm, takich jak pierwsze wydania IEEE 754 i język C ), „denormalny” jest używany wyłącznie w odniesieniu do liczb podnormalnych. To użycie utrzymuje się w różnych dokumentach normatywnych, zwłaszcza przy omawianiu sprzętu, który nie jest w stanie reprezentować żadnych innych zdenormalizowanych liczb, ale w dyskusji tutaj użyto terminu subnormal zgodnie z rewizją IEEE 754 z 2008 roku .

W normalnej wartości zmiennoprzecinkowej nie ma wiodących zer w mantysie ( mantysa ); raczej wiodące zera są usuwane przez dostosowanie wykładnika (na przykład liczba 0,0123 byłaby zapisana jako 1,23 × 10-2 ) . I odwrotnie, zdenormalizowana wartość zmiennoprzecinkowa ma mantysę z cyfrą wiodącą zero. Spośród nich liczby podnormalne reprezentują wartości, które po znormalizowaniu miałyby wykładniki poniżej najmniejszego reprezentowalnego wykładnika (wykładnik mający ograniczony zakres).

00 Mantysa (lub mantysa) liczby zmiennoprzecinkowej IEEE to część liczby zmiennoprzecinkowej reprezentująca cyfry znaczące . Dla dodatniej znormalizowanej liczby można ją przedstawić jako m . m 1 m 2 m 3 ... m p −2 m p −1 (gdzie m reprezentuje cyfrę znaczącą, a p jest precyzją) z niezerowym m . Zauważ, że dla podstawy binarnej , wiodącą cyfrą binarną jest zawsze 1. W liczbie podnormalnej, ponieważ wykładnik jest najmniejszy z możliwych, zero jest wiodącą cyfrą znaczącą (0, m 1 m 2 m 3 ... m p -2 m p - 1 ), umożliwiając reprezentację liczb bliższych zeru niż najmniejsza normalna liczba. Liczbę zmiennoprzecinkową można uznać za podnormalną, gdy jej wykładnik ma najmniejszą możliwą wartość.

Wypełniając lukę niedomiaru w ten sposób, cyfry znaczące są tracone, ale nie tak gwałtownie, jak w przypadku zastosowania przepłukiwania do zera przy podejściu niedomiaru (odrzucanie wszystkich cyfr znaczących po osiągnięciu niedomiaru). Stąd wytwarzanie liczby poniżej normy jest czasami nazywane stopniowym niedomiarem , ponieważ pozwala obliczeniu na powolną utratę precyzji, gdy wynik jest mały.

W standardzie IEEE 754-2008 liczby nienormalne są nazywane liczbami podnormalnymi i są obsługiwane zarówno w formacie binarnym, jak i dziesiętnym. W binarnych formatach wymiany liczby niższe od normalnych są kodowane z wykładnikiem odchylonym od 0, ale są interpretowane z wartością najmniejszego dozwolonego wykładnika, który jest o jeden większy (tj. tak, jakby były zakodowane jako 1). W formatach wymiany dziesiętnej nie wymagają one specjalnego kodowania, ponieważ format obsługuje bezpośrednio liczby nieznormalizowane.

Matematycznie rzecz biorąc, znormalizowane liczby zmiennoprzecinkowe danego znaku są rozmieszczone w przybliżeniu logarytmicznie i jako takie normalne liczby zmiennoprzecinkowe o skończonych rozmiarach nie mogą zawierać zera . Podnormalne zmiennoprzecinkowe są liniowo rozmieszczonymi zbiorami wartości, które obejmują lukę między ujemnymi i dodatnimi normalnymi zmiennoprzecinkowymi.

Tło

Liczby podnormalne dają gwarancję, że dodawanie i odejmowanie liczb zmiennoprzecinkowych nigdy nie będzie niedomiarem; dwie pobliskie liczby zmiennoprzecinkowe zawsze mają reprezentatywną różnicę różną od zera. Bez stopniowego niedomiaru odejmowanie a - b może mieć niedomiar i dać zero, nawet jeśli wartości nie są równe. To z kolei może prowadzić do dzielenia przez zero , które nie mogą wystąpić przy stosowaniu stopniowego niedomiaru.

Liczby nienormalne zostały zaimplementowane w Intel 8087 podczas pisania standardu IEEE 754. Były zdecydowanie najbardziej kontrowersyjną cechą formatu KCS , która została ostatecznie przyjęta, ale ta implementacja pokazała, że ​​​​liczby poniżej normalnych mogą być obsługiwane w praktycznej implementacji. Niektóre implementacje jednostek zmiennoprzecinkowych nie obsługują bezpośrednio liczb poniżej normy w sprzęcie, ale raczej pułapkę na pewnego rodzaju wsparcie programowe. Chociaż może to być niewidoczne dla użytkownika, może to spowodować, że obliczenia, które generują lub zużywają liczby poniżej normalnych, będą znacznie wolniejsze niż podobne obliczenia na normalnych liczbach.

Problemy z wydajnością

Niektóre systemy obsługują sprzętowe wartości poniżej normy w taki sam sposób, jak wartości normalne. Inni pozostawiają obsługę wartości poniżej normy oprogramowaniu systemowemu („pomoc”), obsługując tylko wartości normalne i zero sprzętowe. Obsługa wartości poniżej normy w oprogramowaniu zawsze prowadzi do znacznego spadku wydajności. Gdy wartości poniżej normy są całkowicie obliczane sprzętowo, istnieją techniki implementacji umożliwiające ich przetwarzanie z szybkościami porównywalnymi do normalnych liczb. Jednak szybkość obliczeń pozostaje znacznie zmniejszona w przypadku wielu nowoczesnych procesorów x86; w skrajnych przypadkach instrukcje z operandami nienormalnymi może zająć nawet 100 dodatkowych cykli zegara, powodując, że najszybsze instrukcje działają nawet sześć razy wolniej.

Ta różnica prędkości może stanowić zagrożenie dla bezpieczeństwa. Badacze wykazali, że zapewnia to boczny kanał synchronizacji , który umożliwia złośliwej witrynie internetowej wyodrębnienie zawartości strony z innej witryny w przeglądarce internetowej.

Niektóre aplikacje muszą zawierać kod, aby uniknąć liczb poniżej normalnych, albo w celu zachowania dokładności, albo w celu uniknięcia spadku wydajności w niektórych procesorach. Na przykład w aplikacjach do przetwarzania dźwięku wartości poniżej normy zwykle reprezentują sygnał tak cichy, że jest poza zasięgiem ludzkiego słuchu. Z tego powodu powszechnym sposobem uniknięcia stanów poniżej normalnych na procesorach, w przypadku których wystąpiłby spadek wydajności, jest odcięcie sygnału do zera, gdy osiągnie on poziomy poniżej normy lub dodanie bardzo cichego sygnału szumowego. Inne metody zapobiegania liczbom poniżej normy obejmują dodanie przesunięcia DC, kwantyzację liczb, dodanie sygnału Nyquista itp. Ponieważ SSE2 procesora, firma Intel zapewniła taką funkcjonalność w sprzęcie procesora, która zaokrągla liczby poniżej normy do zera.

Wyłączanie pływaków nienormalnych na poziomie kodu

Intel SSE

Kompilatory C i Fortran firmy Intel domyślnie włączają flagi DAZ (denormals-are-zero) i FTZ (flush-to-zero) dla SSE dla poziomów optymalizacji wyższych niż -O0 . Efektem DAZ jest traktowanie nienormalnych argumentów wejściowych dla operacji zmiennoprzecinkowych jako zero, a efektem FTZ jest zwracanie zera zamiast nienormalnego zmiennoprzecinkowego dla operacji, które skutkowałyby nienormalnym zmiennoprzecinkowym, nawet jeśli argumenty wejściowe nie są same w sobie nienormalny. clang i gcc mają różne stany domyślne w zależności od platformy i poziomu optymalizacji.

Niezgodna z C99 metoda włączania flag DAZ i FTZ na obiektach docelowych obsługujących SSE jest podana poniżej, ale nie jest powszechnie obsługiwana. Wiadomo, że działa na Mac OS X co najmniej od 2006 roku.

 




 #include  <fenv.h>  #pragma STDC FENV_ACCESS ON  // Ustawia DAZ i FTZ, blokując inne ustawienia CSR.  // Zobacz https://opensource.apple.com/source/Libm/Libm-287.1/Source/Intel/, fenv.c i fenv.h.  parametry  (  FE_DFL_DISABLE_SSE_DENORMS_ENV  );  // fesetenv(FE_DFL_ENV) // Wyłącz oba, blokując inne ustawienia CSR. 

W przypadku innych platform x86-SSE, na których biblioteka C nie zaimplementowała jeszcze tej flagi, mogą działać następujące rozwiązania:

 
    
    
    
    #include  <xmmintrin.h>  _mm_setcsr  (  _mm_getcsr  ()  |  0x0040  );  // DAZ  _mm_setcsr  (  _mm_getcsr  ()  |  0x8000  );  // FTZ  _mm_setcsr  (  _mm_getcsr  ()  |  0x8040  );  // Oba  _mm_setcsr  (  _mm_getcsr  ()  &  ~  0x8040  );  // Wyłącz oba 

Makra _MM_SET_DENORMALS_ZERO_MODE i _MM_SET_FLUSH_ZERO_MODE otaczają bardziej czytelny interfejs dla powyższego kodu.


 


 
 // Aby włączyć DAZ  #include  <pmmintrin.h>  _MM_SET_DENORMALS_ZERO_MODE  (  _MM_DENORMALS_ZERO_ON  );  // Aby włączyć FTZ  #include  <xmmintrin.h>  _MM_SET_FLUSH_ZERO_MODE  (  _MM_FLUSH_ZERO_ON  ); 

Większość kompilatorów domyślnie zapewnia już poprzednie makro, w przeciwnym razie można użyć następującego fragmentu kodu (definicja dla FTZ jest analogiczna):






 #define _MM_DENORMALS_ZERO_MASK 0x0040  #define _MM_DENORMALS_ZERO_ON 0x0040  #define _MM_DENORMALS_ZERO_OFF 0x0000  #define _MM_SET_DENORMALS_ZERO_MODE(tryb) _mm_setcsr((_mm_getcsr() & ~_MM_D ENORMALS_ZERO_MASK) | (tryb)) #define _MM_GET_DENORMALS_ZERO_MODE() (  _mm_getcsr() & _MM_DENORMALS_ZERO_MASK) 

Domyślne zachowanie denormalizacji jest wymagane przez ABI i dlatego dobrze działające oprogramowanie powinno zapisywać i przywracać tryb denormalizacji przed powrotem do programu wywołującego lub kodu wywołującego w innych bibliotekach.

RAMIĘ

AArch32 NEON (SIMD) FPU zawsze korzysta z trybu od zera do zera, który jest taki sam jak FTZ + DAZ . Dla skalarnego FPU i w AArch64 SIMD zachowanie od zera do zera jest opcjonalne i kontrolowane przez bit FZ rejestru kontrolnego – FPSCR w Arm32 i FPCR w AArch64.

Niektóre procesory ARM mają sprzętową obsługę stanów podnormalnych.

Zobacz też

Dalsza lektura

  • Zobacz także różne artykuły na stronie internetowej Williama Kahana [1] aby znaleźć przykłady sytuacji, w których liczby poniżej normalnych pomagają poprawić wyniki obliczeń.