,
AOA 14AOA 14, inforamtyka, art of assembly language
[ Pobierz całość w formacie PDF ]
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& WYŁĄCZNOŚĆ DO PUBLIKOWANIA TEGO TŁUMACZENIA POSIADA RAG „THE ART OF ASSEMBLY LANGUAGE” tłumaczone by KREMIK Konsultacje naukowe: NEKRO wankenob@priv5.onet.pl nekro@pf.pl &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ROZDZIAŁ CZTERNASTY: ARYTMETYKA ZMIENNO PRZECINKOWA Chociaż liczby całkowite dostarczają dokładnej reprezentacji dla wartości liczbowych, cierpią one z powodu dwóch głównych wad: niemożność przedstawiania liczb ułamkowych i ograniczenie zakresu dynamiki. Arytmetyka zmienno przecinkowa rozwiązuje te dwa problemy kosztem dokładności i, na niektórych procesorach . szybkości. Większość programistów jest świadomych utraty szybkości związanej z arytmetyką zmienno przecinkową; jednakże są beztrosko nieświadomi problemów z dokładnością. Dla wielu aplikacji korzyści ze zmienno przecinkowości przeważają nad wadami. Jednakże dla właściwego zastosowania arytmetyki zmienno przecinkowej w każdym programie musimy nauczyć się jak działa arytmetyka zmienno przecinkowa. Intel , rozumiejąc znaczenie arytmetyki zmienno przecinkowej w nowoczesnych programach dostarczył wsparcia dla arytmetyki zmienno przecinkowej w najwcześniejszym swoim projekcie 8086 – FPU 8087 (jednostka zmienno przecinkowa lub koprocesor matematyczny). Jednak na procesorach wcześniejszych niż 80486 (lub na 80486sx) procesor zmienno przecinkowy jest urządzeniem opcjonalnym; to znaczy, że nieobecne urządzenie musi być zasymulowane programowo. Rozdział ten zawiera cztery główne sekcje. Pierwsza sekcja omawia arytmetykę zmienno przecinkową z punktu widzenia matematycznego. Druga sekcja omawia binarną postać zmienno przecinkowości powszechnie używanej w procesorach Intela. Trzecia omawia zmienno przecinkowość programową i podprogramy matematyczne ze Standardowej Biblioteki UCR. Czwarta omawia chip 80x87 FPU. 14.0 WSTĘP Ten rozdział zawiera cztery główne sekcje: opis formatu zmienno przecinkowego i operacji (dwie sekcje), omówienie wsparcia zmienno przecinkowości w Bibliotece Standardowej UCR i omówienie 80x87 FPU (jednostki zmienno przecinkowej). Poniższe sekcje które maja znak „•” są niezbędne. Sekcje z „⊗” omawiają tematy zaawansowane, które możemy chcieć opuścić. • Matematyczna arytmetyka zmienno przecinkowa • Formaty zmienno przecinkowe IEEE • Podprogramy zmienno przecinkowe Biblioteki Standardowej UCR • Koprocesor zmienno przecinkowy 80x87 • Instrukcje przesuwania danych FPU ⊗ Konwersje • Instrukcje arytmetyczne • Instrukcje porównań ⊗ Instrukcje stałe ⊗ Instrukcje transcendentalne ⊗ Instrukcje różnorodne ⊗ Operacje całkowite ⊗ Dodatkowe operacje trygonometryczne 14.1 MATEMATYCZNA ARYTMETYKA ZMIENNO PRZECINKOWA Dużym problem z arytmetyką zmienno przecinkową jest taki, że nie stosuje standardowych zasad. Niemniej jednak wielu programistów stosuje normalne zasady algebraiczne kiedy stosuje arytmetykę zmienno przecinkową. Jest to źródło błędów w wielu programach. Jednym z podstawowych celów tej sekcji jest opisanie ograniczeń arytmetyki zmienno przecinkowej, więc zrozumiemy jak stosować ją właściwie. Zwykłe zasady algebraiczne stosują tylko arytmetykę o nieskończonej precyzji. Rozważmy prostą instrukcję x: = x +1, x jest liczbą całkowitą. Na nowoczesnych komputerach ta instrukcja będzie korzystała ze zwykłych zasad algebry , tak długo dopóki nie wystąpi przepełnienie. To znaczy ta instrukcja jest poprawna tylko Rysunek 14.1: Prosty format zmienno przecinkowy dla pewnych wartości x (minint <= x < maxint). Większość programistów nie ma z tym problemu, ponieważ są świadomi faktu, że liczby całkowite w programie nie stosują się do standardowych zasad algebraicznych (np. 5 / 2 ≠ 2.5). Liczby całkowite nie stosują się do standardowych zasad algebry ponieważ ich komputerowa reprezentacja ma skończoną liczbę bitów. Nie możemy przedstawić żadnej (całkowitej) wartości powyżej maksymalnej liczby całkowitej lub poniżej minimalnej liczby całkowitej. Wartości zmienno przecinkowe cierpią na ten sam problem, tylko gorzej. Jednak liczby całkowite są podzbiorem liczb rzeczywistych. Dlatego też wartości zmienno przecinkowe muszą przedstawiać taki sam nieskończony zbiór liczb całkowitych. Jednak jest nieskończona liczba wartości pomiędzy dwoma wartościami rzeczywistymi, więc ten problem jest nieskończenie gorszy. Dlatego też mając ograniczone wartości pomiędzy zakresem maksymalnym a minimalnym, nie możemy przedstawić również wszystkich wartości pomiędzy tymi dwoma zakresami. Do przedstawienia liczb rzeczywistych większość formatów zmienno przecinkowych stosuje notację naukową i używa jakiejś liczby bitów do przedstawiania mantysy i mniejszej liczby bitów do przedstawienia wykładnika. Końcowy rezultat jest taki, że liczba zmienno przecinkowa może tylko przedstawiać liczby z określoną liczbą znaczących cyfr. Ma to duży wpływ na to jak działa arytmetyka zmienno przecinkowa. Łatwo zobaczymy wpływ arytmetyki o ograniczonej precyzji, kiedy przyjmiemy uproszczony format dziesiętny zmienno przecinkowy dla naszych przykładów. Nasz format zmienno przecinkowy dostarczy mantysy z trzema znaczącymi cyframi i dziesiętny wykładnik z dwoma cyframi. Mantysy i wykładniki są wartościami ze znakiem (zobacz rysunek 14.1) Kiedy dodajemy i odejmujemy dwie liczby w notacji naukowej, musimy zmodyfikować dwie wartości, żeby ich wykładniki były takie same. Na przykład, kiedy dodajemy 1.23e1 i 4,56e0, musimy zmodyfikować wartości tak, żeby miały takie same wykładniki. Jednym sposobem zrobienia jest tego jest skonwertowanie 4.56e0 do 0.456e1 a potem je dodać. Todaje1.686e1. Niestety wynik nie mieści się w trzech znaczących cyfrach, wiec musimy zaokrąglić lub skrócić wynik do trzech znaczących cyfr. Zaokrąglanie, generalni, tworzy bardziej precyzyjny wynik, więc zaokrąglamy wynik do 1.69e1. Jak widzimy, brak precyzji (liczba cyfr lub bitów w obliczeniu) wpływa na dokładność (poprawność obliczenia) W poprzednim przykładzie mogliśmy zaokrąglić wynik ponieważ mieliśmy cztery znaczące cyfry podczas obliczania. Jeśli nasze obliczenia zmienno są ograniczone do trzech znaczących liczb podczas obliczania, musimy obciąć ostatnią cyfrę mniejszej liczby uzyskując 1.86e1, które jest mniej poprawne. Dodatkowa cyfra dostępna podczas obliczania jest znana jako pozycja chroniona wyniku (lub bit zabezpieczenia w przypadku formatu bitowego). One wielce podnoszą dokładność podczas długiego szeregu obliczeń. Strata dokładności podczas pojedynczego obliczenia zazwyczaj nie jest taka aby się martwić , chyba ,że martwisz się rzeczywiście precyzją swoich obliczeń. Jednakże jeśli obliczamy wartość , która jest wynikiem sekwencji operacji zmienno przecinkowych, błąd może się gromadzić wielce wpływając na sam wynik. Przypuśćmy na przykład, że dodamy 1.23e3 z 1.00e0. Modyfikując liczby tak, żeby ich wykładniki były takie same przed dodawaniem uzyskujemy 1.23e3 + 0.001e3 . Suma tych dwóch wartości , nawet po zaokrągleniu to 1.23e3. To może wydać się nam zupełnie racjonalne; w końcu możemy tylko zajmować się trzema znaczącymi cyframi, dodanie małej wartości nie powinno wcale wpłynąć na wynik. Jednak przypuśćmy, że będziemy dodawać 1.00e0 do 1.23e3 dziesięć razy. Pierwszy raz dodając 1.00e0 do 1.23e3 dostajemy 1.23e0. Podobnie uzyskamy taki sam wynik za drugim, trzecim, czwartym...dziesiątym razem. Z drugiej strony dodając 1.00e0 do samej siebie dziesięć razy , a potem dodając wynik (1.00e1) do 1.23e3 otrzymamy inny wynik , 1.24e3. Jest ważna rzecz do zapamiętania w arytmetyce o ograniczonej precyzji : Porządek wyliczenia może wpływać na precyzję wyniku Uzyskamy bardziej dokładny wynik jeśli odpowiednie wielkości (to znaczy wykładniki) są bliżej jeden drugiego Jeśli wykonujemy szereg operacji wymagających dodawania i odejmowania, powinniśmy zgrupować właściwe wartości. Inny problem z dodawaniem i odejmowaniem jest taki, że możemy skończyć z fałszywą precyzją. Rozpatrzmy obliczenie 1.23e0 – 1.22e0. Daje to 0.01e0. Chociaż jest to równoważne matematycznie 1.00e-2, ta druga postać wskazuje na to, że ostatnie dwie cyfry są dokładnie zerami. Niestety mamy tylko pojedynczą znaczącą cyfrę tym razem. Rzeczywiście, niektóre FPU lub pakiet oprogramowania zmienno przecinkowego może rzeczywiście mogą wprowadzać losowe cyfry lub bity na najmniej znaczące pozycje. Jest to druga ważna zasada dotycząca arytmetyki o ograniczonej precyzji: Kiedykolwiek odejmujemy dwie liczby z takimi samymi znakami lub dodajemy dwie liczby z różnymi znakami, precyzja wyniku może być mniejsza niż precyzja dostępna w formacie zmienno przecinkowym. Mnożenie i dzielenie nie cierpi z tego samego powodu co dodawanie i odejmowanie ponieważ nie musimy modyfikować wykładników przed tymi działaniami; wszystko co musimy zrobić to dodać wykładniki i pomnożyć mantysy (lub odjąć wykładniki i podzielić mantysy). Mnożenie i dzielenie nie tworzą szczególnie słabych wyników. Jednakże mają one skłonności do zwielokrotniania błędów , które już istnieją w wartości. Na przykład, jeśli pomnożymy 1.23e0 przez dwa, kiedy powinniśmy pomnożyć 1.24e0 przez dwa, wynik jest tym bardziej niedokładny. To daje nam trzecią ważną zasadę kiedy pracujemy z arytmetyką o ograniczonej precyzji: Kiedy wykonujemy łańcuch obliczeń wymagających dodawania, odejmowania mnożenia i dzielenia, próbujemy najpierw wykonać mnożenie i dzielenie. Często, przez zastosowanie normalnych transformacji algebraicznych, możemy ułożyć obliczenia tak, że mnożenie i dzielenie wystąpią najpierw. Na przykład ,przypuśćmy, że chcemy obliczyć x* (y+z). Zwykle dodajemy razem y i z a potem ich sumę mnożymy przez z. Jednakże uzyskamy trochę bardziej dokładny wynik jeśli przetransformujemy x*(y+z) do x*y + x*z i obliczymy wynik, najpierw obliczając mnożenie. Mnożenie i dzielenie też nie są pozbawione problemów. Kiedy mnożymy dwie bardzo duże lub bardzo małe liczby, jest całkiem możliwe wystąpienie przepełnienia lub niedomiaru. Taka sama sytuacja wystąpi kiedy dzielimy małą liczbę przez dużą lub dużą przez małą. Daje to nam czwartą zasadę , którą powinniśmy próbować stosować kiedy mnożymy lub dzielimy wartości: Kiedy mnożymy lub dzielimy zbiór liczb, próbujmy ułożyć mnożenia tak, żeby mnożyć duże i małe liczby razem; podobnie próbujmy dzielić liczby, które maja takie same względne wartości. Porównywanie liczb zmienno przecinkowych jest bardzo niebezpieczne. Ze względu na nieścisłości obecne w obliczeniach (wliczając konwersję ciągu wejściowego na wartość zmienno przecinkową) nie powinniśmy nigdy porównywać dwóch wartości zmienno przecinkowych aby zobaczyć czy są równe. W binarnym formacie zmienno przecinkowym , różne obleczenia , które tworzą taki sam wynik (matematyczny) mogą różnić się w swoich najmniej znaczących bitach. Na przykład dodając 1.31e0 + 1.69e0 powinniśmy otrzymać 3.00e0. podobnie dodając 2.50e0 + 0.50e0 powinniśmy otrzymać 3.00e0. Jednakże porównując (1.31e0+1.69e0) i (2.50e0 + 0.50e0) możemy odkryć, że sumy te nie są równe jedna drugiej. Test dla równości jest pozytywny wtedy i tylko wtedy kiedy wszystkie bity (lub cyfry) w dwóch argumentach są takie same. Ponieważ nie jest to koniecznie prawda ,po dwóch różnych obliczeniach zmienno przecinkowych , które powinny tworzyć taki sam wynik, prosty test na równość może nie działać. Standardowym sposobem dla sprawdzenia równości miedzy liczbami zmienno przecinkowymi jest określenie na jaki błąd (lub jaką tolerancję) pozwolimy w porównaniu i sprawdzamy czy jedna wartość znajduje się wewnątrz zakresu błędu innej. Prostym sposobem zrobienia tego jest użycie testu takiego jak poniższy: if Value1 >= (value2 – błąd) i Value1 <= (Value2 + błąd) then .... innym popularnym sposobem wykonania tego samego porównania jest zastosowanie instrukcji w postaci: if abs (Value1 – Value2) <= błąd then.... Większość tekstów które omawiają porównania zmienno przecinkowe zatrzymuje się bezpośrednio po omówieniu problemu równości , zakładając, że inne formy porównań są zupełnie OK. dla liczb zmienno przecinkowych. To nie jest prawda! Jeśli założymy, że x = y i jeśli x jest wewnątrz y ± błąd, wtedy proste porównanie na poziomie bitowym x i y określi, że x < y jeśli y jest większe niż x ale mniejsze niż y ± błąd. Jednakże w takim przypadku x powinno być potraktowane rzeczywiście jako równe y , nie mniejsze niż y. Dlatego też musimy zawsze porównywać dwie liczby zmienno przecinkowe przy użyciu zakresów, bez względu na rzeczywiste porównanie jakie chcemy wykonać. Próbując porównywać dwie liczby zmienno przecinkowe bezpośrednio może prowadzić do błędu. Dla porównania dwóch liczb zmienno przecinkowych xi y, powinniśmy użyć jedną z poniższych form: = if abs(x-y) <= błąd then.... ≠ if abs(x-y) > błąd then..... < if (x-y) < błąd then..... ≤ if (x-y) <= błąd then... > if (x-y) > błąd then.... ≥ if (x-y) >= błąd then... Musimy postępować ostrożnie kiedy wybieramy wartość błędu. Powinna to być wartość odrobinę większa niż największa ilość błędów, jakie wkradną się do naszych obliczeń. Dokładna wartość będzie zależała od określonego formatu zmienno przecinkowego jakiego używamy, ale więcej o tym, trochę później. Końcową zasadą tej sekcji jest: Kiedy porównujemy dwie liczby zmienno przecinkowe, zawsze porównujemy jedną wartość aby zobaczyć czy jest ona w zakresie danym przez drugą wartość, plus minus jakaś mała wartość błędu. Jest wiele innych problemów, które mogą wystąpić kiedy stosujemy wartości zmienno przecinkowe. Ten tekst może tylko wskazać główne problemy i uświadomić na fakt, że nie możemy traktować arytmetyki zmienno przecinkowej tak jak rzeczywistej arytmetyki – niedokładności obecne w arytmetyce o ograniczonej precyzji mogą spowodować wiele kłopotów jeśli nie będziemy ostrożni. Dobry tekst o analizie numerycznej lub obliczeniach naukowych może pomóc wypełnić szczegóły, które są poza zakresem tego tekstu. Jeśli będziemy pracowali z arytmetyką zmienno przecinkowa, w jakimś języku, powinniśmy znaleźć czas na przestudiowanie wpływu arytmetyki o ograniczonej na nasze obliczenia. 14.2 FORMAT ZMIENNO PRZECINKOWY IEEE Kiedy Intel planował wprowadzenie koprocesora zmienno przecinkowego dla swoich nowych mikroprocesorów 8086, dość elegancko zrealizowali to inżynierowie elektrycy i fizycy, którzy zaprojektowali chipy, być może nie najlepsi ludzie do wykonania koniecznej analizy numerycznej i do wybrania najlepszej możliwie binarnej reprezentacji dla formatu zmienno przecinkowego. Więc Intel wynajął najlepszego analityka numerycznego, który mógł znaleźć pomysł na format zmienno przecinkowy dla ich FPY 8087.Osoba ta wynajęła innych ekspertów w terenie a trzech z nich (Kahn, Coonan i Stone ) zaprojektowali Intelowski format zmienno przecinkowy. Wykonali tak dobrą robotę projektując Standard Zmienno Przecinkowy KCS, że organizacja IEE zaadoptowała go dla formatu zmienno przecinkowego IEEE. Do wymaganego działania w szerokim zakresie wydajności i precyzji Intel w rzeczywistości wprowadził trzy formaty zmienno przecinkowe: o pojedynczej precyzji, podwójnej precyzji i precyzji podwyższonej. Pojedyncza i podwójna precyzja odpowiadają typom float i double z C lub typom real i double z FORTRAN’a. Intel zmierzał do użycia precyzji podwyższonej dla długiego łańcucha obliczeń. Podwyższona precyzja zawiera 16 dodatkowych bitów które Rysunek 14.2: Bity formatu pojedynczej precyzji zmienno przecinkowej dla obliczenia mogą być używane jako bity zabezpieczenia przed zaokrąglaniem w dół do wartości podwójnej precyzji, kiedy przechowują wynik. Format pojedynczej precyzji używa uzupełnionej jedynkami 24 bitowej mantysy i ośmiu bitów nadwyżki – 128 wykładnika. Mantysa zazwyczaj przedstawia wartość pomiędzy 1.0 a 2.0. Najbardziej znaczący bit mantysy jest zazwyczaj jedynką i przedstawia wartość na lewo od przecinka dwójkowego. Pozostałe 23 bity mantysy pojawiają się na prawo od przecinak dwójkowego. Dlatego mantysa reprezentuje wartość : 1.mmmmmmm mmmmmmmm mmmmmmmm Znaki „mmmmmm....” przedstawiają 23 bity mantysy. Zapamiętajmy, że pracujemy tu z liczbami binarnymi. Dlatego każda pozycja na prawo od przecinka binarnego przedstawia wartość (zero lub jeden) razy następujące po sobie ujemne potęgi dwójki. Jeden założony bit jest zawsze mnożony przez 2 0 , czyli jeden. Jest tak dlatego, że mantysa jest zawsze większa niż lub równa jeden. Nawet jeśli wszystkie bity mantysy są zerami, założony jeden bit zawsze daje nam zero. Oczywiście, nawet jeśli mieliśmy prawie nieskończoną liczbę bitów jeden po przecinku binarnym nie mogą one zsumować się do dwóch. Jest tak ponieważ mantysa może reprezentować wartości w zakresie od jeden do dwóch. Chociaż jest nieskończona liczba wartości pomiędzy jeden i dwa ,możemy tylko przedstawić osiem milionów z nich ponieważ mamy 23 bity mantysy ( 24 bity to zawsze jeden). To jest powód niedokładności w arytmetyce zmienno przecinkowej – jesteśmy ograniczeni do 23 bitowej precyzji w obliczeniach wymagających wartości o pojedynczej precyzji zmienno przecinkowej. Mantysa używa formatu uzupełnienia jedynkami zamiast uzupełnienia do dwóch. To znaczy, że 24 bitowa mantysy jest po prostu bez znakową liczbą binarną a bit znaku określa czy wartość ta jest dodatnia czy ujemna. Liczby uzupełnione jedynkami mają niezwykła właściwość, którą są dwie reprezentacje zera 9 z ustawionym bitem znaku i wyzerowanym) . generalnie jest to ważne tylko dla osób projektujących oprogramowanie zmienno przecinkowe lub system sprzętowy. My założymy, że wartość zera ma zawsze wyzerowany znak bitu. Przy przedstawianiu wartości poza zakresem 1.0 do 2.0, wchodzi do gry część wykładnika formatu zmienno przecinkowego. Format zmienno przecinkowy podnosi dwa do potęgi określonej przez wykładnik a potem mnoży mantysę przez tą wartość. Wykładnik jest ośmio bitowy i jest przechowywany w formacie nadmiarowym-127. W formacie tym wykładnik 2 0 jest reprezentowany przez wartość 127 (7fh). Dlatego też konwersja wykładnika do formatu nadmairu-127 to po prostu dodanie 127 do wartości wykładnika. Stosowanie formatu nadmiaru-127 czyni łatwiejszym porównywanie wartości zmienno przecinkowych. Format pojedynczej precyzji zmienno przecinkowej przybiera postać pokazaną na rysunku 14.2 Z 24 bitową mantysą możemy uzyskać w przybliżeniu uzyskać precyzję 6- ½ cyfr (połówka precyzji cyfry oznacza, że pierwsze sześć cyfr może być w zakresie 0..9 ale siódma cyfra może być tylko w zakresie 0...x gdzie x < 9 i generalnie jest blisko pięć). Z ośmio bitowym wyk³adnikiem nadmiaru-128 Rysunek 14.3: Format 64 bitowej podwójnej precyzji zmienno przecinkowej Rysunek 14.4: Format 80 bitej podwyższonej precyzji zmienno przecinkowej zakres dynamiki liczb zmienno przecinkowych o pojedynczej precyzji to w przybliżeniu 2 ±128 do 10 ±38 . Chociaż liczby zmienno przecinkowe o pojedynczej precyzji są odpowiednie dla wielu aplikacji, zakres dynamiki jest czasami za mały dal wielu aplikacji naukowych a duże ograniczenie dokładności jest nie odpowiednie dla wielu finansowych, naukowych i innych aplikacji. Co więcej w długim łańcuchu obliczeniowym ograniczenie dokładności formatu pojedynczej precyzji może wprowadzać poważne błędy. Format podwójnej precyzji pomaga przezwyciężyć problemy pojedynczej precyzji zmienno przecinkowej. Używając dwóch obszarów, format podwójnej precyzji ma 11 bitów nadmiar-1023 wykładnika i 53 bity mantysy ( z niejawnym bardziej znaczącym bite jako jedynką) plus znak bitu. Dostarcza to dynamiki zakresu od około 10 ±308 i 14-1/2 precyzji cyfr, wystarczającą dal większości aplikacji. Wartości zmienno przecinkowe o podwójnej precyzji przybierają postać jak pokazano na rysunku 14.3 Żeby móc zapewnić dokładność podczas długiego łańcucha obliczeń liczb zmienno przecinkowych o podwójnej precyzji. Intel zaprojektował format o podwyższonej precyzji. Format podwyższonej dokładności używa 80 bitów. Dwanaście z szesnastu dodatkowych bitów jest połączonych z mantysą, cztery z dodatkowych bitów jest dołączonych na koniec wykładnika. W odróżnieniu od wartości od pojedynczej i podwójnej precyzji, format podwyższonej precyzji nie ma niejawnego bardziej znaczącego bitu, który jest zawsze jedynką. Dlatego format podwyższonej precyzji dostarcza 64 bitowej mantysy, 15 bitów wykładnika nadmiar – 16383 i jednego bitu znaku. Format dla wartości zmienno przecinkowej o podwyższonej precyzji jest pokazany na rysunku 14.4 W FPU 80x87 i CPU 80486 wszystkie obliczenia są robione przy użyciu postaci o podwyższonej precyzji. Kiedykolwiek ładujemy wartość o pojedynczej lub podwójnej precyzji, FPU automatycznie konwertuje je do wartości o rozszerzonej precyzji. Podobnie, kiedy przechowujemy wartość o pojedynczej lub podwójnej [ Pobierz całość w formacie PDF ] |
Podobne
|