X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=ghc%2Flib%2Fstd%2FPrelNum.lhs;h=48ed0d956373317893d1ffbd8685f51b65d6b9d5;hb=e921b2e307532e0f30eefa88b11a124be592bde4;hp=f70f7269ec0f1170c154ca6067892b77166da508;hpb=f7989a6dea8c43352f363117d9bb07439953ccdc;p=ghc-hetmet.git diff --git a/ghc/lib/std/PrelNum.lhs b/ghc/lib/std/PrelNum.lhs index f70f726..48ed0d9 100644 --- a/ghc/lib/std/PrelNum.lhs +++ b/ghc/lib/std/PrelNum.lhs @@ -4,6 +4,15 @@ \section[PrelNum]{Module @PrelNum@} +The class + + Num + +and the type + + Integer + + \begin{code} {-# OPTIONS -fno-implicit-prelude #-} @@ -15,16 +24,16 @@ import PrelList import PrelEnum import PrelShow -infixr 8 ^, ^^, ** -infixl 7 %, /, `quot`, `rem`, `div`, `mod` infixl 7 * infixl 6 +, - +default () -- Double isn't available yet, + -- and we shouldn't be using defaults anyway \end{code} %********************************************************* %* * -\subsection{Standard numeric classes} +\subsection{Standard numeric class} %* * %********************************************************* @@ -41,104 +50,20 @@ class (Eq a, Show a) => Num a where fromInt (I# i#) = fromInteger (S# i#) -- Go via the standard class-op if the -- non-standard one ain't provided +\end{code} -class (Num a, Ord a) => Real a where - toRational :: a -> Rational - -class (Real a, Enum a) => Integral a where - quot, rem, div, mod :: a -> a -> a - quotRem, divMod :: a -> a -> (a,a) - toInteger :: a -> Integer - toInt :: a -> Int -- partain: Glasgow extension - - n `quot` d = q where (q,_) = quotRem n d - n `rem` d = r where (_,r) = quotRem n d - n `div` d = q where (q,_) = divMod n d - n `mod` d = r where (_,r) = divMod n d - divMod n d = if signum r == negate (signum d) then (q-1, r+d) else qr - where qr@(q,r) = quotRem n d - -class (Num a) => Fractional a where - (/) :: a -> a -> a - recip :: a -> a - fromRational :: Rational -> a - - recip x = 1 / x - x / y = x * recip y - -class (Fractional a) => Floating a where - pi :: a - exp, log, sqrt :: a -> a - (**), logBase :: a -> a -> a - sin, cos, tan :: a -> a - asin, acos, atan :: a -> a - sinh, cosh, tanh :: a -> a - asinh, acosh, atanh :: a -> a - - x ** y = exp (log x * y) - logBase x y = log y / log x - sqrt x = x ** 0.5 - tan x = sin x / cos x - tanh x = sinh x / cosh x - -class (Real a, Fractional a) => RealFrac a where - properFraction :: (Integral b) => a -> (b,a) - truncate, round :: (Integral b) => a -> b - ceiling, floor :: (Integral b) => a -> b - - truncate x = m where (m,_) = properFraction x - - round x = let (n,r) = properFraction x - m = if r < 0 then n - 1 else n + 1 - in case signum (abs r - 0.5) of - -1 -> n - 0 -> if even n then n else m - 1 -> m - - ceiling x = if r > 0 then n + 1 else n - where (n,r) = properFraction x - - floor x = if r < 0 then n - 1 else n - where (n,r) = properFraction x - -class (RealFrac a, Floating a) => RealFloat a where - floatRadix :: a -> Integer - floatDigits :: a -> Int - floatRange :: a -> (Int,Int) - decodeFloat :: a -> (Integer,Int) - encodeFloat :: Integer -> Int -> a - exponent :: a -> Int - significand :: a -> a - scaleFloat :: Int -> a -> a - isNaN, isInfinite, isDenormalized, isNegativeZero, isIEEE - :: a -> Bool - atan2 :: a -> a -> a - - - exponent x = if m == 0 then 0 else n + floatDigits x - where (m,n) = decodeFloat x - - significand x = encodeFloat m (negate (floatDigits x)) - where (m,_) = decodeFloat x - - scaleFloat k x = encodeFloat m (n+k) - where (m,n) = decodeFloat x - - atan2 y x - | x > 0 = atan (y/x) - | x == 0 && y > 0 = pi/2 - | x < 0 && y > 0 = pi + atan (y/x) - |(x <= 0 && y < 0) || - (x < 0 && isNegativeZero y) || - (isNegativeZero x && isNegativeZero y) - = -atan2 (-y) x - | y == 0 && (x < 0 || isNegativeZero x) - = pi -- must be after the previous test on zero y - | x==0 && y==0 = y -- must be after the other double zero tests - | otherwise = x + y -- x or y is a NaN, return a NaN (via +) +A few small numeric functions +\begin{code} +subtract :: (Num a) => a -> a -> a +{-# INLINE subtract #-} +subtract x y = y - x + +ord_0 :: Num a => a +ord_0 = fromInt (ord '0') \end{code} + %********************************************************* %* * \subsection{Instances for @Int@} @@ -157,57 +82,228 @@ instance Num Int where | n `eqInt` 0 = 0 | otherwise = 1 - fromInteger (S# i#) = I# i# - fromInteger (J# s# d#) - = case (integer2Int# s# d#) of { i# -> I# i# } + fromInteger n = integer2Int n + fromInt n = n +\end{code} - fromInt n = n -instance Real Int where - toRational x = toInteger x % 1 +\begin{code} +-- These can't go in PrelBase with the defn of Int, because +-- we don't have pairs defined at that time! -instance Integral Int where - a@(I# _) `quotRem` b@(I# _) = (a `quotInt` b, a `remInt` b) +quotRemInt :: Int -> Int -> (Int, Int) +a@(I# _) `quotRemInt` b@(I# _) = (a `quotInt` b, a `remInt` b) -- OK, so I made it a little stricter. Shoot me. (WDP 94/10) - -- Following chks for zero divisor are non-standard (WDP) - a `quot` b = if b /= 0 - then a `quotInt` b - else error "Prelude.Integral.quot{Int}: divide by 0" - a `rem` b = if b /= 0 - then a `remInt` b - else error "Prelude.Integral.rem{Int}: divide by 0" - - x `div` y = if x > 0 && y < 0 then quotInt (x-y-1) y - else if x < 0 && y > 0 then quotInt (x-y+1) y - else quotInt x y - x `mod` y = if x > 0 && y < 0 || x < 0 && y > 0 then - if r/=0 then r+y else 0 - else - r - where r = remInt x y - - divMod x@(I# _) y@(I# _) = (x `div` y, x `mod` y) +divModInt :: Int -> Int -> (Int, Int) +divModInt x@(I# _) y@(I# _) = (x `divInt` y, x `modInt` y) -- Stricter. Sorry if you don't like it. (WDP 94/10) +\end{code} + + +%********************************************************* +%* * +\subsection{The @Integer@ type} +%* * +%********************************************************* + +\begin{code} +data Integer + = S# Int# -- small integers + | J# Int# ByteArray# -- large integers +\end{code} + +Convenient boxed Integer PrimOps. + +\begin{code} +zeroInteger :: Integer +zeroInteger = S# 0# ---OLD: even x = eqInt (x `mod` 2) 0 ---OLD: odd x = neInt (x `mod` 2) 0 +int2Integer :: Int -> Integer +{-# INLINE int2Integer #-} +int2Integer (I# i) = S# i - toInteger (I# i) = int2Integer i -- give back a full-blown Integer - toInt x = x +integer2Int :: Integer -> Int +integer2Int (S# i) = I# i +integer2Int (J# s d) = case (integer2Int# s d) of { n# -> I# n# } +addr2Integer :: Addr# -> Integer +{-# INLINE addr2Integer #-} +addr2Integer x = case addr2Integer# x of (# s, d #) -> J# s d + +toBig (S# i) = case int2Integer# i of { (# s, d #) -> J# s d } +toBig i@(J# _ _) = i \end{code} + %********************************************************* %* * -\subsection{Instances for @Integer@} +\subsection{Dividing @Integers@} %* * %********************************************************* \begin{code} -toBig (S# i) = case int2Integer# i of { (# s, d #) -> J# s d } -toBig i@(J# _ _) = i +quotRemInteger :: Integer -> Integer -> (Integer, Integer) +quotRemInteger (S# i) (S# j) + = case quotRemInt (I# i) (I# j) of ( I# i, I# j ) -> ( S# i, S# j ) +quotRemInteger i1@(J# _ _) i2@(S# _) = quotRemInteger i1 (toBig i2) +quotRemInteger i1@(S# _) i2@(J# _ _) = quotRemInteger (toBig i1) i2 +quotRemInteger (J# s1 d1) (J# s2 d2) + = case (quotRemInteger# s1 d1 s2 d2) of + (# s3, d3, s4, d4 #) + -> (J# s3 d3, J# s4 d4) + +divModInteger (S# i) (S# j) + = case divModInt (I# i) (I# j) of ( I# i, I# j ) -> ( S# i, S# j) +divModInteger i1@(J# _ _) i2@(S# _) = divModInteger i1 (toBig i2) +divModInteger i1@(S# _) i2@(J# _ _) = divModInteger (toBig i1) i2 +divModInteger (J# s1 d1) (J# s2 d2) + = case (divModInteger# s1 d1 s2 d2) of + (# s3, d3, s4, d4 #) + -> (J# s3 d3, J# s4 d4) + +remInteger :: Integer -> Integer -> Integer +remInteger ia 0 + = error "Prelude.Integral.rem{Integer}: divide by 0" +remInteger (S# a) (S# b) + = S# (remInt# a b) +remInteger ia@(S# a) (J# sb b) + | sb ==# 1# = S# (remInt# a (word2Int# (integer2Word# sb b))) + | sb ==# -1# = S# (remInt# a (0# -# (word2Int# (integer2Word# sb b)))) + | 0# <# sb = ia + | otherwise = S# (0# -# a) +remInteger (J# sa a) (S# b) + = case int2Integer# b of { (# sb, b #) -> + case remInteger# sa a sb b of { (# sr, r #) -> + S# (sr *# (word2Int# (integer2Word# sr r))) }} +remInteger (J# sa a) (J# sb b) + = case remInteger# sa a sb b of (# sr, r #) -> J# sr r + +quotInteger :: Integer -> Integer -> Integer +quotInteger ia 0 + = error "Prelude.Integral.quot{Integer}: divide by 0" +quotInteger (S# a) (S# b) + = S# (quotInt# a b) +quotInteger (S# a) (J# sb b) + | sb ==# 1# = S# (quotInt# a (word2Int# (integer2Word# sb b))) + | sb ==# -1# = S# (quotInt# a (0# -# (word2Int# (integer2Word# sb b)))) + | otherwise = zeroInteger +quotInteger (J# sa a) (S# b) + = case int2Integer# b of { (# sb, b #) -> + case quotInteger# sa a sb b of (# sq, q #) -> J# sq q } +quotInteger (J# sa a) (J# sb b) + = case quotInteger# sa a sb b of (# sg, g #) -> J# sg g +\end{code} + + + +\begin{code} +gcdInteger :: Integer -> Integer -> Integer +gcdInteger (S# a) (S# b) + = case gcdInt# a b of g -> S# g +gcdInteger ia@(S# a) ib@(J# sb b) + | a ==# 0# = abs ib + | sb ==# 0# = abs ia + | otherwise = case gcdIntegerInt# sb b a of g -> S# g +gcdInteger ia@(J# sa a) ib@(S# b) + | sa ==# 0# = abs ib + | b ==# 0# = abs ia + | otherwise = case gcdIntegerInt# sa a b of g -> S# g +gcdInteger (J# sa a) (J# sb b) + = case gcdInteger# sa a sb b of (# sg, g #) -> J# sg g + +lcmInteger :: Integer -> Integer -> Integer +lcmInteger a 0 + = zeroInteger +lcmInteger 0 b + = zeroInteger +lcmInteger a b + = (divExact aa (gcdInteger aa ab)) * ab + where aa = abs a + ab = abs b + +divExact :: Integer -> Integer -> Integer +divExact (S# a) (S# b) + = S# (quotInt# a b) +divExact (S# a) (J# sb b) + = S# (quotInt# a (sb *# (word2Int# (integer2Word# sb b)))) +divExact (J# sa a) (S# b) + = case int2Integer# b of + (# sb, b #) -> case divExactInteger# sa a sb b of (# sd, d #) -> J# sd d +divExact (J# sa a) (J# sb b) + = case divExactInteger# sa a sb b of (# sd, d #) -> J# sd d +\end{code} + + +%********************************************************* +%* * +\subsection{The @Integer@ instances for @Eq@, @Ord@} +%* * +%********************************************************* + +\begin{code} +instance Eq Integer where + (S# i) == (S# j) = i ==# j + (S# i) == (J# s d) = cmpIntegerInt# s d i ==# 0# + (J# s d) == (S# i) = cmpIntegerInt# s d i ==# 0# + (J# s1 d1) == (J# s2 d2) = (cmpInteger# s1 d1 s2 d2) ==# 0# + + (S# i) /= (S# j) = i /=# j + (S# i) /= (J# s d) = cmpIntegerInt# s d i /=# 0# + (J# s d) /= (S# i) = cmpIntegerInt# s d i /=# 0# + (J# s1 d1) /= (J# s2 d2) = (cmpInteger# s1 d1 s2 d2) /=# 0# + +------------------------------------------------------------------------ +instance Ord Integer where + (S# i) <= (S# j) = i <=# j + (J# s d) <= (S# i) = cmpIntegerInt# s d i <=# 0# + (S# i) <= (J# s d) = cmpIntegerInt# s d i >=# 0# + (J# s1 d1) <= (J# s2 d2) = (cmpInteger# s1 d1 s2 d2) <=# 0# + + (S# i) > (S# j) = i ># j + (J# s d) > (S# i) = cmpIntegerInt# s d i ># 0# + (S# i) > (J# s d) = cmpIntegerInt# s d i <# 0# + (J# s1 d1) > (J# s2 d2) = (cmpInteger# s1 d1 s2 d2) ># 0# + + (S# i) < (S# j) = i <# j + (J# s d) < (S# i) = cmpIntegerInt# s d i <# 0# + (S# i) < (J# s d) = cmpIntegerInt# s d i ># 0# + (J# s1 d1) < (J# s2 d2) = (cmpInteger# s1 d1 s2 d2) <# 0# + + (S# i) >= (S# j) = i >=# j + (J# s d) >= (S# i) = cmpIntegerInt# s d i >=# 0# + (S# i) >= (J# s d) = cmpIntegerInt# s d i <=# 0# + (J# s1 d1) >= (J# s2 d2) = (cmpInteger# s1 d1 s2 d2) >=# 0# + + compare (S# i) (S# j) + | i ==# j = EQ + | i <=# j = LT + | otherwise = GT + compare (J# s d) (S# i) + = case cmpIntegerInt# s d i of { res# -> + if res# <# 0# then LT else + if res# ># 0# then GT else EQ + } + compare (S# i) (J# s d) + = case cmpIntegerInt# s d i of { res# -> + if res# ># 0# then LT else + if res# <# 0# then GT else EQ + } + compare (J# s1 d1) (J# s2 d2) + = case cmpInteger# s1 d1 s2 d2 of { res# -> + if res# <# 0# then LT else + if res# ># 0# then GT else EQ + } +\end{code} + + +%********************************************************* +%* * +\subsection{The @Integer@ instances for @Num@} +%* * +%********************************************************* +\begin{code} instance Num Integer where (+) i1@(S# i) i2@(S# j) = case addIntC# i j of { (# r, c #) -> @@ -258,90 +354,21 @@ instance Num Integer where fromInteger x = x fromInt (I# i) = S# i +\end{code} -instance Real Integer where - toRational x = x % 1 - -instance Integral Integer where - -- ToDo: a `rem` b returns a small integer if b is small, - -- a `quot` b returns a small integer if a is small. - quotRem (S# i) (S# j) - = case quotRem (I# i) (I# j) of ( I# i, I# j ) -> ( S# i, S# j) - quotRem i1@(J# _ _) i2@(S# _) = quotRem i1 (toBig i2) - quotRem i1@(S# _) i2@(J# _ _) = quotRem (toBig i1) i2 - quotRem (J# s1 d1) (J# s2 d2) - = case (quotRemInteger# s1 d1 s2 d2) of - (# s3, d3, s4, d4 #) - -> (J# s3 d3, J# s4 d4) - - toInteger n = n - toInt (S# i) = I# i - toInt (J# s d) = case (integer2Int# s d) of { n# -> I# n# } - - -- we've got specialised quot/rem methods for Integer (see below) - n `quot` d = n `quotInteger` d - n `rem` d = n `remInteger` d - - n `div` d = q where (q,_) = divMod n d - n `mod` d = r where (_,r) = divMod n d - - divMod (S# i) (S# j) - = case divMod (I# i) (I# j) of ( I# i, I# j ) -> ( S# i, S# j) - divMod i1@(J# _ _) i2@(S# _) = divMod i1 (toBig i2) - divMod i1@(S# _) i2@(J# _ _) = divMod (toBig i1) i2 - divMod (J# s1 d1) (J# s2 d2) - = case (divModInteger# s1 d1 s2 d2) of - (# s3, d3, s4, d4 #) - -> (J# s3 d3, J# s4 d4) - -remInteger :: Integer -> Integer -> Integer -remInteger ia 0 - = error "Prelude.Integral.rem{Integer}: divide by 0" -remInteger (S# a) (S# b) = S# (remInt# a b) -remInteger ia@(S# a) (J# sb b) - = if sb ==# 1# - then - S# (remInt# a (word2Int# (integer2Word# sb b))) - else if sb ==# -1# then - S# (remInt# a (0# -# (word2Int# (integer2Word# sb b)))) - else if 0# <# sb then - ia - else - S# (0# -# a) -remInteger (J# sa a) (S# b) - = case int2Integer# b of { (# sb, b #) -> - case remInteger# sa a sb b of { (# sr, r #) -> - S# (sr *# (word2Int# (integer2Word# sr r))) }} -remInteger (J# sa a) (J# sb b) - = case remInteger# sa a sb b of (# sr, r #) -> J# sr r - -quotInteger :: Integer -> Integer -> Integer -quotInteger ia 0 - = error "Prelude.Integral.quot{Integer}: divide by 0" -quotInteger (S# a) (S# b) = S# (quotInt# a b) -quotInteger (S# a) (J# sb b) - = if sb ==# 1# - then - S# (quotInt# a (word2Int# (integer2Word# sb b))) - else if sb ==# -1# then - S# (quotInt# a (0# -# (word2Int# (integer2Word# sb b)))) - else - zeroInteger -quotInteger (J# sa a) (S# b) - = case int2Integer# b of { (# sb, b #) -> - case quotInteger# sa a sb b of (# sq, q #) -> J# sq q } -quotInteger (J# sa a) (J# sb b) - = case quotInteger# sa a sb b of (# sg, g #) -> J# sg g -zeroInteger :: Integer -zeroInteger = S# 0# +%********************************************************* +%* * +\subsection{The @Integer@ instance for @Enum@} +%* * +%********************************************************* ------------------------------------------------------------------------- +\begin{code} instance Enum Integer where succ x = x + 1 pred x = x - 1 - toEnum n = toInteger n - fromEnum n = toInt n + toEnum n = int2Integer n + fromEnum n = integer2Int n {-# INLINE enumFrom #-} {-# INLINE enumFromThen #-} @@ -390,9 +417,10 @@ dn_list x delta lim = go (x::Integer) #-} \end{code} + %********************************************************* %* * -\subsection{Show code for Integers} +\subsection{The @Integer@ instances for @Show@} %* * %********************************************************* @@ -414,147 +442,7 @@ jtos i rs jtos' :: Integer -> String -> String jtos' n cs | n < 10 = chr (fromInteger n + (ord_0::Int)) : cs - | otherwise = jtos' q (chr (toInt r + (ord_0::Int)) : cs) + | otherwise = jtos' q (chr (integer2Int r + (ord_0::Int)) : cs) where - (q,r) = n `quotRem` 10 - -ord_0 :: Num a => a -ord_0 = fromInt (ord '0') -\end{code} - -%********************************************************* -%* * -\subsection{The @Ratio@ and @Rational@ types} -%* * -%********************************************************* - -\begin{code} -data (Integral a) => Ratio a = !a :% !a deriving (Eq) -type Rational = Ratio Integer - -{-# SPECIALISE (%) :: Integer -> Integer -> Rational #-} -(%) :: (Integral a) => a -> a -> Ratio a -numerator, denominator :: (Integral a) => Ratio a -> a -\end{code} - -\tr{reduce} is a subsidiary function used only in this module . -It normalises a ratio by dividing both numerator and denominator by -their greatest common divisor. - -\begin{code} -reduce :: (Integral a) => a -> a -> Ratio a -reduce _ 0 = error "Ratio.%: zero denominator" -reduce x y = (x `quot` d) :% (y `quot` d) - where d = gcd x y -\end{code} - -\begin{code} -x % y = reduce (x * signum y) (abs y) - -numerator (x :% _) = x -denominator (_ :% y) = y - -\end{code} - -%********************************************************* -%* * -\subsection{Overloaded numeric functions} -%* * -%********************************************************* - -\begin{code} - -{-# SPECIALISE subtract :: Int -> Int -> Int #-} -subtract :: (Num a) => a -> a -> a -subtract x y = y - x - -even, odd :: (Integral a) => a -> Bool -even n = n `rem` 2 == 0 -odd = not . even - -gcd :: (Integral a) => a -> a -> a -gcd 0 0 = error "Prelude.gcd: gcd 0 0 is undefined" -gcd x y = gcd' (abs x) (abs y) - where gcd' a 0 = a - gcd' a b = gcd' b (a `rem` b) - -{-# SPECIALISE lcm :: - Int -> Int -> Int, - Integer -> Integer -> Integer #-} -lcm :: (Integral a) => a -> a -> a -lcm _ 0 = 0 -lcm 0 _ = 0 -lcm x y = abs ((x `quot` (gcd x y)) * y) - -{-# SPECIALISE (^) :: - Integer -> Integer -> Integer, - Integer -> Int -> Integer, - Int -> Int -> Int #-} -(^) :: (Num a, Integral b) => a -> b -> a -_ ^ 0 = 1 -x ^ n | n > 0 = f x (n-1) x - where f _ 0 y = y - f a d y = g a d where - g b i | even i = g (b*b) (i `quot` 2) - | otherwise = f b (i-1) (b*y) -_ ^ _ = error "Prelude.^: negative exponent" - -{- SPECIALISE (^^) :: - Double -> Int -> Double, - Rational -> Int -> Rational #-} -(^^) :: (Fractional a, Integral b) => a -> b -> a -x ^^ n = if n >= 0 then x^n else recip (x^(negate n)) -\end{code} - -%********************************************************* -%* * -\subsection{Specialized versions of gcd/lcm for Int/Integer} -%* * -%********************************************************* - -\begin{code} -{-# RULES -"Int.gcd" forall a b . gcd a b = gcdInt a b -"Integer.gcd" forall a b . gcd a b = gcdInteger a b -"Integer.lcm" forall a b . lcm a b = lcmInteger a b - #-} - -gcdInt :: Int -> Int -> Int -gcdInt (I# a) (I# b) - = I# (gcdInt# a b) - -gcdInteger :: Integer -> Integer -> Integer -gcdInteger (S# a) (S# b) - = case gcdInt# a b of g -> S# g -gcdInteger ia@(S# a) ib@(J# sb b) - | a ==# 0# = abs ib - | sb ==# 0# = abs ia - | otherwise = case gcdIntegerInt# sb b a of g -> S# g -gcdInteger ia@(J# sa a) ib@(S# b) - | sa ==# 0# = abs ib - | b ==# 0# = abs ia - | otherwise = case gcdIntegerInt# sa a b of g -> S# g -gcdInteger (J# sa a) (J# sb b) - = case gcdInteger# sa a sb b of (# sg, g #) -> J# sg g - -lcmInteger :: Integer -> Integer -> Integer -lcmInteger a 0 - = zeroInteger -lcmInteger 0 b - = zeroInteger -lcmInteger a b - = (divExact aa (gcdInteger aa ab)) * ab - where aa = abs a - ab = abs b - -divExact :: Integer -> Integer -> Integer -divExact (S# a) (S# b) - = S# (quotInt# a b) -divExact (S# a) (J# sb b) - = S# (quotInt# a (sb *# (word2Int# (integer2Word# sb b)))) -divExact (J# sa a) (S# b) - = case int2Integer# b of - (# sb, b #) -> case divExactInteger# sa a sb b of (# sd, d #) -> J# sd d -divExact (J# sa a) (J# sb b) - = case divExactInteger# sa a sb b of (# sd, d #) -> J# sd d + (q,r) = n `quotRemInteger` 10 \end{code}