--[[ Rational Arithmetic Data Representation Module (Core) H. Conrad Cunningham, Professor Computer and Information Science University of Mississippi Developed for CSci 450/503, Organization of Programming Languages, Fall 2016 This version of the data representation module represents a rational number using a two element Lua array and computes the GCD during the construction of the rational number. 1234567890123456789012345678901234567890123456789012345678901234567890 2016-09-11: Adapted from Haskell RationalCore module This work was based on a Haskell version that was itself adapted from section 2.1 of Abelson and Sussman's _Structure and Interpretation of Computer Programs_ (http://mitpress.mit.edu/sicp/). --]] -- UTILITY FUNCTIONS (not exported) -- Haskell -- signum' :: Int -> Int -- signum' n | n == 0 = 0 -- | n > 0 = 1 -- | n < 0 = -1 -- Assumes n is numeric local function signum(n) if n == 0 then return 0 elseif n > 0 then return 1 else return -1 end end -- Haskell -- gcd' :: Int -> Int -> Int -- gcd' x y = gcd'' (abs' x) (abs' y) -- where gcd'' x 0 = x -- gcd'' x y = gcd'' y (x `rem` y) -- Assumes arguments are integers local function gcd(x,y) local function gcdaux(x,y) if y == 0 then return x else return gcdaux(y, x % y) -- tail recursive end end return gcdaux(math.abs(x), math.abs(y)) end -- RATIONAL ARITHMETIC OPERATORS -- Haskell -- module RationalCore -- (Rat, makeRat, numer, denom, showRat) -- where -- -- type Rat = (Int,Int) -- makeRat :: Int -> Int -> Rat -- makeRat x 0 = error ( "Cannot construct a rational number " -- ++ showRat (x,0) ++ "\n" ) -- makeRat 0 _ = (0,1) -- makeRat x y = (x' `div` d, y' `div` d) -- where x' = (signum' y) * x -- y' = abs' y -- d = gcd' x' y' -- Creates a new rational number without checking whether -- x and y are integers and y nonzero local function newRat(x,y) if x == 0 then return {0,1} else local xx = signum(y) * x local yy = math.abs(y) local d = gcd(xx,yy) return {xx/d, yy/d} end end -- Checks whether arguments are integers for Lua before 5.3 local function makeRat(x,y) if type(x) == "number" and type(y) == "number" and x == math.floor(x) and y == math.floor(y) and y ~= 0 then return newRat(x,y) else error("Cannot construct rational number " .. tostring(x) .. "/" .. tostring(y) ) end end -- Haskell -- numer, denom :: Rat -> Int -- numer (x,_) = x -- denom (_,y) = y -- Assumes r is created by makeRat local function numer(r) return r[1] end -- Assumes r is created by makeRat local function denom(r) return r[2] end -- Should newRat also be exported? return { makeRat = makeRat, numer = numer, denom = denom }