Compare commits
10 commits
2e6f56dfde
...
1bdfde80d7
Author | SHA1 | Date | |
---|---|---|---|
Kiana Sheibani | 1bdfde80d7 | ||
Kiana Sheibani | d19ae136f7 | ||
Kiana Sheibani | 52eb83594b | ||
Kiana Sheibani | e21b81b965 | ||
Kiana Sheibani | 80e43be8fc | ||
Kiana Sheibani | 0dbd3e6bc8 | ||
Kiana Sheibani | 42d216fb98 | ||
Kiana Sheibani | 5a6b7cad3f | ||
Kiana Sheibani | c1bfc2f042 | ||
Kiana Sheibani | fdbc5b9d69 |
2
LICENSE
2
LICENSE
|
@ -1,6 +1,6 @@
|
||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2022 Kiana Sheibani
|
Copyright (c) 2024 Kiana Sheibani
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
package ratio
|
package ratio
|
||||||
|
brief = "Arbitrary-precision ratio types"
|
||||||
version = 1.0.0
|
version = 1.0.0
|
||||||
|
|
||||||
authors = "Kiana Sheibani"
|
authors = "Kiana Sheibani"
|
||||||
|
@ -7,4 +8,5 @@ license = "MIT"
|
||||||
sourcedir = "src"
|
sourcedir = "src"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
|
||||||
modules = Data.Ratio
|
modules = Data.Ratio,
|
||||||
|
Data.IntegralGCD
|
||||||
|
|
|
@ -18,7 +18,7 @@ interface (Eq a, Integral a) => IntegralGCD a where
|
||||||
gcd x y =
|
gcd x y =
|
||||||
if x == 0 then y
|
if x == 0 then y
|
||||||
else if y == 0 then x
|
else if y == 0 then x
|
||||||
else assert_total $ gcd y (x `mod` y)
|
else gcd y (assert_smaller y $ x `mod` y)
|
||||||
|
|
||||||
|
|
||||||
export IntegralGCD Integer where
|
export IntegralGCD Integer where
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
module Data.Ratio
|
module Data.Ratio
|
||||||
|
|
||||||
|
import Data.Bool.Xor
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
import Data.So
|
import Data.So
|
||||||
import Data.IntegralGCD
|
import Data.IntegralGCD
|
||||||
|
@ -25,35 +26,6 @@ Rational : Type
|
||||||
Rational = Ratio Integer
|
Rational = Ratio Integer
|
||||||
|
|
||||||
|
|
||||||
||| Reduce a ratio by dividing both components by their common factor. Most
|
|
||||||
||| operations automatically reduce the returned ratio, so explicitly calling
|
|
||||||
||| this function is usually unnecessary.
|
|
||||||
export
|
|
||||||
reduce : IntegralGCD a => Ratio a -> Ratio a
|
|
||||||
reduce (MkRatio n d) =
|
|
||||||
let g = gcd n d in MkRatio (n `div` g) (d `div` g)
|
|
||||||
|
|
||||||
|
|
||||||
||| Construct a ratio of two values, returning `Nothing` if the denominator is
|
|
||||||
||| zero.
|
|
||||||
export
|
|
||||||
mkRatioMaybe : IntegralGCD a => (n, d : a) -> Maybe (Ratio a)
|
|
||||||
mkRatioMaybe n d = toMaybe (d /= 0) (reduce $ MkRatio n d)
|
|
||||||
|
|
||||||
infix 9 //
|
|
||||||
|
|
||||||
||| Construct a ratio of two values.
|
|
||||||
export
|
|
||||||
(//) : IntegralGCD a => (n, d : a) -> {auto 0 ok : So (d /= 0)} -> Ratio a
|
|
||||||
(//) n d = reduce $ MkRatio n d
|
|
||||||
|
|
||||||
|
|
||||||
||| Round a ratio down to a positive integer.
|
|
||||||
export
|
|
||||||
floor : Integral a => Ratio a -> a
|
|
||||||
floor (MkRatio n d) = n `div` d
|
|
||||||
|
|
||||||
|
|
||||||
namespace Ratio
|
namespace Ratio
|
||||||
||| Return the numerator of the ratio in reduced form.
|
||| Return the numerator of the ratio in reduced form.
|
||||||
export %inline
|
export %inline
|
||||||
|
@ -78,6 +50,46 @@ namespace Ratio
|
||||||
(.denom) = dn
|
(.denom) = dn
|
||||||
|
|
||||||
|
|
||||||
|
||| Reduce a ratio by dividing both components by their common factor. Most
|
||||||
|
||| operations automatically reduce the returned ratio, so explicitly calling
|
||||||
|
||| this function is usually unnecessary.
|
||||||
|
export
|
||||||
|
reduce : IntegralGCD a => Ratio a -> Ratio a
|
||||||
|
reduce (MkRatio n d) =
|
||||||
|
let g = gcd n d in MkRatio (n `div` g) (d `div` g)
|
||||||
|
|
||||||
|
||| Construct a ratio of two values, returning `Nothing` if the denominator is
|
||||||
|
||| zero.
|
||||||
|
export
|
||||||
|
mkRatioMaybe : IntegralGCD a => (n, d : a) -> Maybe (Ratio a)
|
||||||
|
mkRatioMaybe n d = toMaybe (d /= 0) (reduce $ MkRatio n d)
|
||||||
|
|
||||||
|
||| Create a ratio of two values.
|
||||||
|
export partial
|
||||||
|
mkRatio : IntegralGCD a => (n, d : a) -> Ratio a
|
||||||
|
mkRatio n d = case d /= 0 of
|
||||||
|
True => reduce $ MkRatio n d
|
||||||
|
|
||||||
|
||| Create a ratio of two values, unsafely assuming that they are coprime and
|
||||||
|
||| the denominator is non-zero.
|
||||||
|
||| WARNING: This function will behave erratically and may crash your program
|
||||||
|
||| if these conditions are not met!
|
||||||
|
export %unsafe
|
||||||
|
unsafeMkRatio : (n, d : a) -> Ratio a
|
||||||
|
unsafeMkRatio = MkRatio
|
||||||
|
|
||||||
|
infix 9 //
|
||||||
|
|
||||||
|
||| Construct a ratio of two values.
|
||||||
|
export
|
||||||
|
(//) : IntegralGCD a => (n, d : a) -> {auto 0 ok : So (d /= 0)} -> Ratio a
|
||||||
|
(//) n d = reduce $ MkRatio n d
|
||||||
|
|
||||||
|
|
||||||
|
||| Round a ratio down to the nearest integer less than it.
|
||||||
|
export
|
||||||
|
floor : Integral a => Ratio a -> a
|
||||||
|
floor (MkRatio n d) = n `div` d
|
||||||
|
|
||||||
|
|
||||||
export
|
export
|
||||||
|
@ -87,12 +99,12 @@ Eq a => Eq (Ratio a) where
|
||||||
export
|
export
|
||||||
(Ord a, Num a) => Ord (Ratio a) where
|
(Ord a, Num a) => Ord (Ratio a) where
|
||||||
compare (MkRatio n d) (MkRatio m b) =
|
compare (MkRatio n d) (MkRatio m b) =
|
||||||
flipIfNeg (b*d) $ compare (n*b) (m*d)
|
flipIf (b >= 0 `xor` d >= 0) $ compare (n*b) (m*d)
|
||||||
where
|
where
|
||||||
flipIfNeg : a -> Ordering -> Ordering
|
flipIf : Bool -> Ordering -> Ordering
|
||||||
flipIfNeg x EQ = EQ
|
flipIf _ EQ = EQ
|
||||||
flipIfNeg x LT = if x >= 0 then LT else GT
|
flipIf b LT = if b then GT else LT
|
||||||
flipIfNeg x GT = if x >= 0 then GT else LT
|
flipIf b GT = if b then LT else GT
|
||||||
|
|
||||||
export
|
export
|
||||||
Show a => Show (Ratio a) where
|
Show a => Show (Ratio a) where
|
||||||
|
@ -120,3 +132,18 @@ IntegralGCD a => Fractional (Ratio a) where
|
||||||
recip (MkRatio n d) = case n /= 0 of True => MkRatio d n
|
recip (MkRatio n d) = case n /= 0 of True => MkRatio d n
|
||||||
MkRatio n d / MkRatio m b = case m /= 0 of
|
MkRatio n d / MkRatio m b = case m /= 0 of
|
||||||
True => reduce $ MkRatio (n*b) (m*d)
|
True => reduce $ MkRatio (n*b) (m*d)
|
||||||
|
|
||||||
|
-- ## Casting
|
||||||
|
|
||||||
|
export
|
||||||
|
Num a => Cast a (Ratio a) where
|
||||||
|
cast x = MkRatio x 1
|
||||||
|
|
||||||
|
export
|
||||||
|
Cast a b => Cast (Ratio a) (Ratio b) where
|
||||||
|
cast (MkRatio n d) = MkRatio (cast n) (cast d)
|
||||||
|
|
||||||
|
-- Special case: `Cast Rational Double`
|
||||||
|
export
|
||||||
|
(Cast a b, Fractional b) => Cast (Ratio a) b where
|
||||||
|
cast (MkRatio n d) = cast n / cast d
|
||||||
|
|
Loading…
Reference in a new issue