Wieża numeryczna

W Scheme i zainspirowanych nim dialektach Lispa wieża numeryczna to zestaw typów danych reprezentujących liczby i logikę ich hierarchicznej organizacji.

Reprezentacja wieży numerycznej z pięcioma typami liczb.

Każdy typ w wieży koncepcyjnie „siedzi” na bardziej podstawowym typie, więc liczba całkowita jest liczbą wymierną i liczbą , ale sytuacja odwrotna niekoniecznie jest prawdziwa, tj. nie każda liczba jest liczbą całkowitą. Ta asymetria implikuje, że język może bezpiecznie zezwalać na niejawne wymuszanie typów liczbowych — bez tworzenia problemów semantycznych — tylko w jednym kierunku: przekształcanie liczby całkowitej na wymierną nie powoduje utraty żadnych informacji i nigdy nie wpłynie na wartość zwracaną przez funkcję, ale wymusza większość liczb rzeczywistych do liczby całkowitej zmieniłoby wszelkie odpowiednie obliczenia (np. rzeczywista 1/3 nie równa się żadnej liczbie całkowitej), a zatem jest niedopuszczalne.

W Lispie

Zasadniczo wieża numeryczna ma na celu kodyfikację właściwości teorii mnogości liczb w łatwym do zaimplementowania narzędziu językowym: każda liczba całkowita jest liczbą wymierną z ukrytym mianownikiem 1, a wszystkie liczby rzeczywiste są złożone z ukrytą częścią urojoną równą imaginary part of 0. Practically, the implementation may save time and space by ignoring these properties unless they become arithmetically relevant, and also may correspondingly improve the efficiency of its representation when reducing numerical values to their canonical representation by eliminating negligible components of a number.

Najbardziej ogólny typ, number , ma nieco mylącą nazwę: istnieje, aby przechwytywać wszystkie wartości matematyczne, których typ jest bardziej ogólny niż złożony , ale które nadal nadają się do użytku ze standardowymi operacjami matematycznymi, zgodnie z definicją Scheme. W ten sposób wychwytuje na przykład dodatnią i ujemną nieskończoność ( +inf.0 i -inf.0 , mantys oznacza tutaj przybliżenie do liczność), ponieważ są to obiekty matematyczne, do których można prawidłowo zastosować przynajmniej niektóre operacje numeryczne (np. można dodawać lub mnożyć przez nieskończoność, uzyskując nieskończoność; lub porównywać liczność z nieskończonością, przy czym nieskończoność jest zawsze większa niż dowolna wartość skończona). Na bardziej technicznym poziomie liczba w Lisp po prostu zapewnia miejsce w hierarchii typów dla rodzajów wartości nieściśle liczbowych zdefiniowanych przez IEEE 754 .

Język programowania Scheme definiuje całą swoją arytmetykę w ramach tego modelu, podobnie jak większość innych dialektów Lispa. Niektóre implementacje mogą rozszerzać lub dostosowywać wieżę. Kawa , implementacja schematu dla JVM , rozszerza wieżę, aby obejmowała zarówno kwaterniony , jak i ilości, przy czym ilości są sposobem na podtypowanie wartości liczbowych za pomocą jednostek; np. liczba gramów nie może być sensownie dodana do liczby metrów , ponieważ poprzez ilości liczby dziedziczą logikę wyprowadzoną z analizy wymiarowej rządzić ich znaczeniem w odniesieniu do, a tym samym prawidłowymi interakcjami arytmetycznymi między sobą.

Inną powszechną odmianą jest obsługa zarówno dokładnych, jak i niedokładnych wersji wieży lub jej części; R 7 RS Scheme zaleca, ale nie wymaga tego bezwzględnie od wdrożeń. W tym przypadku podobna semantyka jest używana do określenia dopuszczalności ukrytego przymusu: niedokładność jest zaraźliwą właściwością liczb, a każda operacja numeryczna obejmująca zarówno dokładne, jak i niedokładne wartości musi dawać niedokładne wartości zwracane o co najmniej takiej samej precyzji, jak najbardziej precyzyjne niedokładne wartości . liczba występująca w wyrażeniu, chyba że precyzja jest praktycznie nieskończona (np. zawiera wykrywalne powtórzenie ) lub chyba że można udowodnić, że dokładność wyniku operacji jest niezależna od niedokładności któregokolwiek z jej operandów (na przykład seria mnożeń, w których co najmniej jedna mnożna wynosi 0).

W innych językach

Większość języków programowania i implementacji języków nie obsługuje wieży liczbowej podobnej do schematu, chociaż niektóre języki zapewniają ograniczone lub niespójne wsparcie, jeśli pozwala na to prostota implementacji. Na przykład Python zapewnia podobną strukturę za pośrednictwem PEP3141, cytując przykład Scheme, chociaż w praktyce liczby wymierne ( ułamki ) muszą być importowane z własnego modułu, a zarówno liczby wymierne, jak i liczby zespolone używają składni nieco odmiennej od normalnych literałów liczbowych, ponieważ składnia Pythona jest mniej wyraźny niż Lisp.

Tak więc w poniższych przykładach schematów widzimy:

  
 
 
 

 

               
 
                     
 0
 0 1  -2  +3  1  -2  3  1  /3  1  /3  72  /6+8/3i  12  +8/3i  ; przymus: forma kanoniczna   (  +  3  +2i  2-2  i  )  5  ; przymus: forma kanoniczna   (  -  3-62  /32i  1  +inf  .  i  )  2  -inf  .  I              
 
                     ; przymus: nieskończona liczność   (  >  3  +0/2i  3  )  #f  ; przymus: 3 ≯ 3  

Podczas gdy w poniższych przykładach Pythona widzimy:

  
 
 
 

 
                         
   
   
    1  ;  -  2  ;  +  3  1  -  2  3  1  /  3  0.33333333333333333  inf  =  float  (  'inf'  )  # nieskończoność nie pierwszej klasy  z  ułamków  import  Ułamek  x  =  Ułamek  (  1  ,  3  )  y  =  Ułamek  (  2  ,  3  ) 
  
                           

 
 
               
  
   x  +  y  Ułamek  (  1  ,  1  )  # brak przymusu  (  3  +  2  j  )  (  3  +  2  j  )  złożony  (  x  ,  inf  )  (  0,33333333333333333  +  infj  )  # przymus: równość naruszona  a  =  1  /  3  b  =  Ułamek  (  1  
   0
   0
  
 
  
                                    
   
                                
 ,  3  )  caz  =  złożony  (  a  ,  )  cbz  =  złożony  (  b  ,  )  a  ==  b  Fałsz  caz  ==  cbz  Prawda  # dowód naruszenia równości  złożony  (  x  +  y  ,  -  inf  )  (  1  -  infj  )  # przymus: równość zachowana  (  3 0  
     
          
           +  j  )  >  3  Traceback  (  ostatnie  wywołanie  jako  ostatnie  ):  Plik  „<stdin>”  ,  wiersz  1  ,  w  <  module  >  #  bez wymuszenia: błąd typu  Błąd typu  :  „>”  nieobsługiwany  między  instancjami „   complex  i  'int' 

W przykładach Pythona możemy zobaczyć, że problemy liczbowe pojawiają się swobodnie przy niespójnym zastosowaniu semantyki jego typu przymusu. Podczas gdy 1/3 w Pythonie jest traktowane jako wywołanie dzielenia 1 przez 3, dające liczbę zmiennoprzecinkową, włączenie liczb wymiernych do liczby zespolonej, choć wyraźnie dozwolone, pośrednio przekształca je z liczb wymiernych w liczby zmiennoprzecinkowe lub całkowite, nawet w przypadkach, gdy jest to błędny.

Smalltalk to kolejny język programowania, który jest zgodny z tym modelem, ale ma ArithmeticValue i Magnitude jako nadklasy Liczby.

  1. ^ „Poprawiony raport 7 dotyczący schematu języka algorytmicznego: 6.2.4: Rozszerzenia implementacji” (PDF) .
  2. ^ „Poprawiony raport 5 dotyczący schematu języka algorytmicznego: 6.2.1: typy numeryczne” (PDF) .
  3. ^ „Poprawiony raport 7 dotyczący schematu języka algorytmicznego: 6.2.1: typy numeryczne” (PDF) .
  4. ^ „Dokumentacja referencyjna Kawa: 12.4. Quaternions” .
  5. ^ „Dokumentacja referencyjna Kawa: 12,5 ilości i jednostek” .
  6. ^ „Poprawiony raport 7 dotyczący schematu języka algorytmicznego: 6.2.2: Dokładność” (PDF) .
  7. ^ „PEP 3141 - Hierarchia typów dla liczb” .