Liczba podnormalna - Subnormal number

Nierozszerzony system zmiennoprzecinkowy zawierałby tylko znormalizowane liczby (oznaczone na czerwono). Dopuszczenie liczb zdenormalizowanych (kolor niebieski) rozszerza zasięg systemu.

W informatyce , numery niedorozwinięty są podzbiorem nieznormalizowana numerów (czasami nazywane denormals ), które wypełniają niedopełnienie szczelinę wokół zera w arytmetyki zmiennoprzecinkowej . Każda niezerowa liczba o wielkości mniejszej niż najmniejsza liczba normalna jest podnormalna .

Uwaga dotycząca użycia: w niektórych starszych dokumentach (zwłaszcza w dokumentach standardów, takich jak pierwsze wydania IEEE 754 i języka C ), słowo „denormalne” jest używane wyłącznie w odniesieniu do liczb podnormalnych. To użycie występuje w różnych dokumentach normatywnych, zwłaszcza w przypadku omawiania sprzętu, który nie jest w stanie reprezentować żadnych innych zdenormalizowanych liczb, ale w niniejszym omówieniu użyto terminu podnormalne zgodnie z rewizją IEEE 754 z 2008 roku .

W normalnej wartości zmiennoprzecinkowej nie ma wiodących zer w znaczącej ( mantysa ); raczej początkowe zera są usuwane przez dostosowanie wykładnika (na przykład liczba 0,0123 zostanie zapisana jako 1,23 × 10 -2 ). Odwrotnie, zdenormalizowana wartość zmiennoprzecinkowa ma znaczący z cyfrą wiodącą wynoszącą zero. Spośród nich liczby subnormalne reprezentują wartości, które po znormalizowaniu miałyby wykładniki poniżej najmniejszego możliwego do przedstawienia wykładnika (wykładnik o ograniczonym zakresie).

Znacząca (lub mantysa) liczby zmiennoprzecinkowej IEEE jest częścią liczby zmiennoprzecinkowej, która reprezentuje cyfry znaczące . Dla dodatniej znormalizowanej liczby można ją przedstawić jako m 0 . m 1 m 2 m 3 ... m p -2 m p -1 (gdzie m oznacza cyfrę znaczącą, a p jest precyzją) z niezerowym m 0 . Zauważ, że dla podstawy dwójkowej , wiodąca cyfra dwójkowa to zawsze 1. W liczbie podnormalnej, ponieważ wykładnik jest najmniejszym możliwym, 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 liczba normalna. Liczbę zmiennoprzecinkową można uznać za podnormalną, gdy jej wykładnik jest najmniejszą możliwą wartością.

Wypełniając lukę niedomiaru w ten sposób, znaczące cyfry są tracone, ale nie tak nagle, jak w przypadku użycia spłukiwania do zera przy podejściu niedomiaru (odrzucanie wszystkich znaczących cyfr po osiągnięciu niedomiaru). Dlatego tworzenie liczby podnormalnej jest czasami nazywane stopniowym niedomiarem, ponieważ pozwala na powolną utratę precyzji obliczeń, gdy wynik jest mały.

W standardzie IEEE 754-2008 liczby nienormalne są przemianowane na liczby podnormalne i są obsługiwane zarówno w formacie binarnym, jak i dziesiętnym. W binarnych formatach wymiany liczby podnormalne są kodowane z wykładnikiem obciążonym równym 0, ale są interpretowane z wartością najmniejszego dozwolonego wykładnika, który jest o jeden większy (tj. tak, jakby był zakodowany jako 1). W formatach wymiany dziesiętnej nie wymagają one specjalnego kodowania, ponieważ format bezpośrednio obsługuje nieznormalizowane liczby.

Matematycznie rzecz biorąc, znormalizowane liczby zmiennoprzecinkowe danego znaku są z grubsza rozmieszczone logarytmicznie i jako takie nie mogą zawierać zero . Pływaki podnormalne są liniowo rozmieszczonymi zestawami wartości, które obejmują lukę między ujemnymi i dodatnimi pływakami normalnymi.

Tło

Liczby podnormalne dają gwarancję, że dodawanie i odejmowanie liczb zmiennoprzecinkowych nigdy nie jest niedostateczne; dwie pobliskie liczby zmiennoprzecinkowe zawsze mają dającą się przedstawić niezerową różnicę. Bez stopniowego niedopełnienia odejmowanie a  -  b może spowodować niedopełnienie i dać zero, nawet jeśli wartości nie są równe. To z kolei może prowadzić do błędów dzielenia przez zero, które nie mogą wystąpić przy stosowaniu stopniowego niedopełnienia.

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

Problemy z wydajnością

Niektóre systemy obsługują wartości subnormalne sprzętowo, w taki sam sposób jak wartości normalne. Inni pozostawiają obsługę wartości podnormalnych oprogramowaniu systemowemu („asystent”), obsługując tylko wartości normalne i zero w sprzęcie. Obsługa wartości podnormalnych w oprogramowaniu zawsze prowadzi do znacznego spadku wydajności. Gdy wartości podnormalne są całkowicie obliczane sprzętowo, istnieją techniki implementacji umożliwiające ich przetwarzanie z szybkością porównywalną do normalnych liczb. Jednak szybkość obliczeń pozostaje znacznie zmniejszona na wielu nowoczesnych procesorach x86; w skrajnych przypadkach instrukcje zawierające podnormalne operandy mogą 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 boczny kanał czasowy, 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ąć podnormalnych liczb, albo w celu zachowania dokładności, albo w celu uniknięcia spadku wydajności niektórych procesorów. Na przykład w zastosowaniach przetwarzania dźwięku wartości podnormalne zwykle reprezentują sygnał tak cichy, że znajduje się poza zasięgiem ludzkiego słuchu. Z tego powodu, powszechnym sposobem uniknięcia subnormalnych na procesorach, gdzie występuje spadek wydajności, jest obcięcie sygnału do zera, gdy osiągnie on poziomy subnormalne lub zmieszanie z wyjątkowo cichym sygnałem szumowym. Inne metody zapobiegania liczbom nienormalnym obejmują dodanie przesunięcia DC, kwantyzację liczb, dodanie sygnału Nyquist itp. Od rozszerzenia procesora SSE2 , Intel zapewnił taką funkcjonalność w sprzęcie CPU, która zaokrągla liczby nienormalne do zera.

Wyłączanie subnormalnych pływaków 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 DAZjest traktowanie podnormalnych argumentów wejściowych dla operacji zmiennoprzecinkowych jako zero, a efektem FTZjest zwracanie zera zamiast wartości zmiennoprzecinkowej nienormalnej dla operacji, które skutkowałyby zmiennością nienormalną, nawet jeśli same argumenty wejściowe nie są nienormalne. clang i gcc mają różne stany domyślne w zależności od platformy i poziomu optymalizacji.

Poniżej podano niezgodną z C99 metodę włączania flag DAZi FTZna obiektach docelowych obsługujących SSE, ale nie jest powszechnie obsługiwana. Wiadomo, że działa na Mac OS X od co najmniej 2006 roku.

#include <fenv.h>
#pragma STDC FENV_ACCESS ON
// Sets DAZ and FTZ, clobbering other CSR settings.
// See https://opensource.apple.com/source/Libm/Libm-287.1/Source/Intel/, fenv.c and fenv.h.
fesetenv(FE_DFL_DISABLE_SSE_DENORMS_ENV);
// fesetenv(FE_DFL_ENV) // Disable both, clobbering other CSR settings.

W przypadku innych platform x86-SSE, w których biblioteka C nie zaimplementowała jeszcze tej flagi, może działać:

#include <xmmintrin.h>
_mm_setcsr(_mm_getcsr() | 0x0040);  // DAZ
_mm_setcsr(_mm_getcsr() | 0x8000);  // FTZ
_mm_setcsr(_mm_getcsr() | 0x8040);  // Both
_mm_setcsr(_mm_getcsr() & ~0x8040); // Disable both

_MM_SET_DENORMALS_ZERO_MODEI _MM_SET_FLUSH_ZERO_MODEmakra owinąć bardziej czytelny interfejs dla powyższego kodu.

// To enable DAZ
#include <pmmintrin.h>
_MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);
// To enable FTZ
#include <xmmintrin.h>
_MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);

Większość kompilatorów domyślnie udostępnia 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(mode) _mm_setcsr((_mm_getcsr() & ~_MM_DENORMALS_ZERO_MASK) | (mode))
#define _MM_GET_DENORMALS_ZERO_MODE()                (_mm_getcsr() &  _MM_DENORMALS_ZERO_MASK)

Domyślne zachowanie denormalizacji jest wymagane przez ABI i dlatego dobrze zachowujące się oprogramowanie powinno zapisać i przywrócić tryb denormalizacji przed powrotem do obiektu wywołującego lub wywołaniem kodu w innych bibliotekach.

RAMIĘ

AArch32 NEON (SIMD) FPU zawsze używa trybu wyrównania do zera, który jest taki sam jak FTZ + DAZ. Dla skalarnego FPU i w AArch64 SIMD zachowanie wyrównania do zera jest opcjonalne i kontrolowane przez FZbit rejestru kontrolnego – FPSCR w Arm32 i FPCR w AArch64.

Niektóre procesory ARM obsługują sprzętową obsługę podnormalnych.

Zobacz też

Bibliografia

Dalsza lektura

  • Zobacz także różne artykuły na stronie internetowej Williama Kahana [1], aby zapoznać się z przykładami, w których liczby subnormalne pomagają poprawić wyniki obliczeń.