121 lines
3.8 KiB
Haskell
121 lines
3.8 KiB
Haskell
{-
|
|
Name: Yuri Tatishchev
|
|
Class: CS 252
|
|
Assigment: HW1
|
|
Date: 2/16/2026
|
|
Description: Big numbers in Haskell
|
|
-}
|
|
|
|
module BigNum (
|
|
BigNum,
|
|
bigAdd,
|
|
bigSubtract,
|
|
bigMultiply,
|
|
bigEq,
|
|
bigDec,
|
|
bigPowerOf,
|
|
prettyPrint,
|
|
stringToBigNum,
|
|
) where
|
|
|
|
type Block = Int -- An Int from 0-999
|
|
|
|
type BigNum = [Block]
|
|
|
|
maxblock = 1000
|
|
|
|
bigAdd :: BigNum -> BigNum -> BigNum
|
|
bigAdd x y = bigAdd' x y 0
|
|
|
|
bigAdd' :: BigNum -> BigNum -> Block -> BigNum
|
|
bigAdd' [] [] 0 = []
|
|
bigAdd' [] [] c = [c]
|
|
bigAdd' (x:xs) (y:ys) c = let s = x + y + c
|
|
in (s `mod` maxblock) : bigAdd' xs ys (s `div` maxblock)
|
|
bigAdd' (x:xs) [] c = let s = x + c
|
|
in (s `mod` maxblock) : bigAdd' xs [] (s `div` maxblock)
|
|
bigAdd' [] (y:ys) c = let s = y + c
|
|
in (s `mod` maxblock) : bigAdd' [] ys (s `div` maxblock)
|
|
|
|
bigSubtract :: BigNum -> BigNum -> BigNum
|
|
bigSubtract x y =
|
|
if length x < length y
|
|
then error "Negative numbers not supported"
|
|
else reverse $ stripLeadingZeroes $ reverse result
|
|
where result = bigSubtract' x y 0
|
|
|
|
stripLeadingZeroes :: BigNum -> BigNum
|
|
stripLeadingZeroes (0:[]) = [0]
|
|
stripLeadingZeroes (0:xs) = stripLeadingZeroes xs
|
|
stripLeadingZeroes xs = xs
|
|
|
|
-- Negative numbers are not supported, so you may throw an error in these cases
|
|
bigSubtract' :: BigNum -> BigNum -> Block -> BigNum
|
|
bigSubtract' [] [] 0 = []
|
|
bigSubtract' [] _ _ = error "Negative numbers not supported"
|
|
bigSubtract' (x:xs) (y:ys) b = let d = x - y - b
|
|
in if d < 0
|
|
then (d + maxblock) : bigSubtract' xs ys 1
|
|
else d : bigSubtract' xs ys 0
|
|
bigSubtract' (x:xs) [] b = let d = x - b
|
|
in if d < 0
|
|
then (d + maxblock) : bigSubtract' xs [] 1
|
|
else d : bigSubtract' xs [] 0
|
|
|
|
bigEq :: BigNum -> BigNum -> Bool
|
|
bigEq x y = stripLeadingZeroes (reverse x) == stripLeadingZeroes (reverse y)
|
|
|
|
bigDec :: BigNum -> BigNum
|
|
bigDec x = bigSubtract x [1]
|
|
|
|
-- Handle multiplication following the same approach you learned in grade
|
|
-- school, except dealing with blocks of 3 digits rather than single digits.
|
|
-- If you are having trouble finding a solution, write a helper method that
|
|
-- multiplies a BigNum by an Int.
|
|
bigMultiply :: BigNum -> BigNum -> BigNum
|
|
bigMultiply x y = reverse $ stripLeadingZeroes $ reverse $ bigMultiply' x y
|
|
|
|
bigMultiply' :: BigNum -> BigNum -> BigNum
|
|
bigMultiply' _ [] = []
|
|
bigMultiply' x (y:ys) = bigAdd (bigMultiplyBlock x y) (bigMultiply (0:x) ys)
|
|
|
|
bigMultiplyBlock :: BigNum -> Block -> BigNum
|
|
bigMultiplyBlock x y = bigMultiplyBlock' x y 0
|
|
|
|
bigMultiplyBlock' :: BigNum -> Block -> Block -> BigNum
|
|
bigMultiplyBlock' [] _ 0 = []
|
|
bigMultiplyBlock' [] _ c = [c]
|
|
bigMultiplyBlock' (x:xs) y c = let p = x * y + c
|
|
in (p `mod` maxblock) : bigMultiplyBlock' xs y (p `div` maxblock)
|
|
|
|
bigPowerOf :: BigNum -> BigNum -> BigNum
|
|
bigPowerOf x [0] = [1]
|
|
bigPowerOf x [1] = x
|
|
bigPowerOf x y = bigMultiply x (bigPowerOf x (bigDec y))
|
|
|
|
prettyPrint :: BigNum -> String
|
|
prettyPrint [] = ""
|
|
prettyPrint xs = show first ++ prettyPrint' rest
|
|
where (first:rest) = reverse xs
|
|
|
|
prettyPrint' :: BigNum -> String
|
|
prettyPrint' [] = ""
|
|
prettyPrint' (x:xs) = prettyPrintBlock x ++ prettyPrint' xs
|
|
|
|
prettyPrintBlock :: Int -> String
|
|
prettyPrintBlock x | x < 10 = ",00" ++ show x
|
|
| x < 100 = ",0" ++ show x
|
|
| otherwise = "," ++ show x
|
|
|
|
stringToBigNum :: String -> BigNum
|
|
stringToBigNum "0" = [0]
|
|
stringToBigNum s = stringToBigNum' $ reverse s
|
|
|
|
stringToBigNum' :: String -> BigNum
|
|
stringToBigNum' [] = []
|
|
stringToBigNum' s | length s <= 3 = read (reverse s) : []
|
|
stringToBigNum' (a:b:c:rest) = block : stringToBigNum' rest
|
|
where block = read $ c:b:a:[]
|
|
|
|
sig = "9102llaf"
|