{-# OPTIONS_GHC -Wno-partial-type-signatures #-}
{-# LANGUAGE PartialTypeSignatures #-}
{-# LANGUAGE TemplateHaskell #-}
module Numeric.MixedTypes.Round
(
CanDivIMod(..)
, CanDivIModIntegerSameType
, CanDivIModIntegerSameTypeCN
, CanRound(..), HasIntegerBounds(..)
, specCanDivIMod, specCanRound, specHasIntegerBounds
)
where
import Utils.TH.DeclForTypes
import Numeric.MixedTypes.PreludeHiding
import qualified Prelude as P
import Text.Printf
import Data.Fixed (divMod')
import Test.Hspec
import Test.QuickCheck as QC
import Numeric.CollectErrors ( CN )
import qualified Numeric.CollectErrors as CN
import Numeric.MixedTypes.Literals
import Numeric.MixedTypes.Bool
import Numeric.MixedTypes.Eq
import Numeric.MixedTypes.Ord
import Numeric.MixedTypes.AddSub
import Numeric.MixedTypes.Ring
class CanDivIMod t1 t2 where
type DivIType t1 t2
type ModType t1 t2
type ModType t1 t2 = t1
divIMod :: t1 -> t2 -> (DivIType t1 t2, ModType t1 t2)
mod :: t1 -> t2 -> ModType t1 t2
mod t1
a t2
b = (DivIType t1 t2, ModType t1 t2) -> ModType t1 t2
forall a b. (a, b) -> b
snd ((DivIType t1 t2, ModType t1 t2) -> ModType t1 t2)
-> (DivIType t1 t2, ModType t1 t2) -> ModType t1 t2
forall a b. (a -> b) -> a -> b
$ t1 -> t2 -> (DivIType t1 t2, ModType t1 t2)
forall t1 t2.
CanDivIMod t1 t2 =>
t1 -> t2 -> (DivIType t1 t2, ModType t1 t2)
divIMod t1
a t2
b
divI :: t1 -> t2 -> DivIType t1 t2
divI t1
a t2
b = (DivIType t1 t2, ModType t1 t2) -> DivIType t1 t2
forall a b. (a, b) -> a
fst ((DivIType t1 t2, ModType t1 t2) -> DivIType t1 t2)
-> (DivIType t1 t2, ModType t1 t2) -> DivIType t1 t2
forall a b. (a -> b) -> a -> b
$ t1 -> t2 -> (DivIType t1 t2, ModType t1 t2)
forall t1 t2.
CanDivIMod t1 t2 =>
t1 -> t2 -> (DivIType t1 t2, ModType t1 t2)
divIMod t1
a t2
b
type CanDivIModIntegerSameType t =
(CanDivIMod t t, DivIType t t ~ Integer, ModType t t ~ t)
type CanDivIModIntegerSameTypeCN t =
(CanDivIMod t t, DivIType t t ~ CN Integer, ModType t t ~ t)
instance CanDivIMod Integer Integer where
type DivIType Integer Integer = Integer
divIMod :: Integer
-> Integer -> (DivIType Integer Integer, ModType Integer Integer)
divIMod = Integer
-> Integer -> (DivIType Integer Integer, ModType Integer Integer)
forall a. Integral a => a -> a -> (a, a)
P.divMod
instance CanDivIMod Integer Int where
type DivIType Integer Int = Integer
divIMod :: Integer -> Int -> (DivIType Integer Int, ModType Integer Int)
divIMod Integer
x Int
m = Integer
-> Integer -> (DivIType Integer Integer, ModType Integer Integer)
forall t1 t2.
CanDivIMod t1 t2 =>
t1 -> t2 -> (DivIType t1 t2, ModType t1 t2)
divIMod Integer
x (Int -> Integer
forall t. CanBeInteger t => t -> Integer
integer Int
m)
instance CanDivIMod Int Integer where
type ModType Int Integer = Integer
type DivIType Int Integer = Integer
divIMod :: Int -> Integer -> (DivIType Int Integer, ModType Int Integer)
divIMod Int
x Integer
m = Integer
-> Integer -> (DivIType Integer Integer, ModType Integer Integer)
forall t1 t2.
CanDivIMod t1 t2 =>
t1 -> t2 -> (DivIType t1 t2, ModType t1 t2)
divIMod (Int -> Integer
forall t. CanBeInteger t => t -> Integer
integer Int
x) Integer
m
instance CanDivIMod Int Int where
type ModType Int Int = Integer
type DivIType Int Int = Integer
divIMod :: Int -> Int -> (DivIType Int Int, ModType Int Int)
divIMod Int
x Int
m = Integer
-> Integer -> (DivIType Integer Integer, ModType Integer Integer)
forall t1 t2.
CanDivIMod t1 t2 =>
t1 -> t2 -> (DivIType t1 t2, ModType t1 t2)
divIMod (Int -> Integer
forall t. CanBeInteger t => t -> Integer
integer Int
x) (Int -> Integer
forall t. CanBeInteger t => t -> Integer
integer Int
m)
instance (CanDivIMod t1 t2, CanTestPosNeg t2) => CanDivIMod (CN t1) (CN t2) where
type DivIType (CN t1) (CN t2) = (CN (DivIType t1 t2))
type ModType (CN t1) (CN t2) = (CN (ModType t1 t2))
divIMod :: CN t1
-> CN t2 -> (DivIType (CN t1) (CN t2), ModType (CN t1) (CN t2))
divIMod CN t1
x CN t2
m
| CN t2 -> Bool
forall t. CanTestPosNeg t => t -> Bool
isCertainlyPositive CN t2
m = (CollectErrors NumErrors (DivIType t1 t2)
DivIType (CN t1) (CN t2)
d, CollectErrors NumErrors (ModType t1 t2)
ModType (CN t1) (CN t2)
xm)
| CN t2 -> Bool
forall t. CanTestPosNeg t => t -> Bool
isCertainlyNegative CN t2
m = (CollectErrors NumErrors (DivIType t1 t2)
-> CollectErrors NumErrors (DivIType t1 t2)
forall v. CN v -> CN v
noval CollectErrors NumErrors (DivIType t1 t2)
d, CollectErrors NumErrors (ModType t1 t2)
-> CollectErrors NumErrors (ModType t1 t2)
forall v. CN v -> CN v
noval CollectErrors NumErrors (ModType t1 t2)
xm)
| Bool
otherwise = (CollectErrors NumErrors (DivIType t1 t2)
-> CollectErrors NumErrors (DivIType t1 t2)
forall v. CN v -> CN v
errPote CollectErrors NumErrors (DivIType t1 t2)
d, CollectErrors NumErrors (ModType t1 t2)
-> CollectErrors NumErrors (ModType t1 t2)
forall v. CN v -> CN v
errPote CollectErrors NumErrors (ModType t1 t2)
xm)
where
(CollectErrors NumErrors (DivIType t1 t2)
d,CollectErrors NumErrors (ModType t1 t2)
xm) = (t1 -> t2 -> (DivIType t1 t2, ModType t1 t2))
-> CN t1
-> CN t2
-> (CollectErrors NumErrors (DivIType t1 t2),
CollectErrors NumErrors (ModType t1 t2))
forall es a b c d.
Monoid es =>
(a -> b -> (c, d))
-> CollectErrors es a
-> CollectErrors es b
-> (CollectErrors es c, CollectErrors es d)
CN.lift2pair t1 -> t2 -> (DivIType t1 t2, ModType t1 t2)
forall t1 t2.
CanDivIMod t1 t2 =>
t1 -> t2 -> (DivIType t1 t2, ModType t1 t2)
divIMod CN t1
x CN t2
m
noval :: CN v -> CN v
noval :: CN v -> CN v
noval = (CN v -> NumError -> CN v) -> NumError -> CN v -> CN v
forall a b c. (a -> b -> c) -> b -> a -> c
flip CN v -> NumError -> CN v
forall t. CN t -> NumError -> CN t
CN.removeValueErrorCertain NumError
err
errPote :: CN t -> CN t
errPote :: CN t -> CN t
errPote = NumError -> CN t -> CN t
forall t. NumError -> CN t -> CN t
CN.prependErrorPotential NumError
err
err :: CN.NumError
err :: NumError
err = String -> NumError
CN.OutOfDomain String
"divIMod: modulus not positive"
$(declForTypes
[[t| Integer |], [t| Int |], [t| Rational |], [t| Double |]]
(\ t -> [d|
instance (CanDivIMod t1 $t) => CanDivIMod (CN t1) $t where
type DivIType (CN t1) $t = (CN (DivIType t1 $t))
type ModType (CN t1) $t = (CN (ModType t1 $t))
divIMod x m
| isCertainlyPositive m = (d, xm)
| isCertainlyNegative m = (noval d, noval xm)
| otherwise = (errPote d, errPote xm)
where
(d,xm) = CN.lift1Tpair divIMod x m
instance (CanDivIMod $t t2, CanTestPosNeg t2) => CanDivIMod $t (CN t2) where
type DivIType $t (CN t2) = (CN (DivIType $t t2))
type ModType $t (CN t2) = (CN (ModType $t t2))
divIMod x m
| isCertainlyPositive m = (d, xm)
| isCertainlyNegative m = (noval d, noval xm)
| otherwise = (errPote d, errPote xm)
where
(d,xm) = CN.liftT1pair divIMod x m
|]))
instance CanDivIMod Rational Rational where
type DivIType Rational Rational = Integer
divIMod :: Rational
-> Rational
-> (DivIType Rational Rational, ModType Rational Rational)
divIMod = Rational
-> Rational
-> (DivIType Rational Rational, ModType Rational Rational)
forall a b. (Real a, Integral b) => a -> a -> (b, a)
divMod'
instance CanDivIMod Rational Integer where
type DivIType Rational Integer = Integer
divIMod :: Rational
-> Integer -> (DivIType Rational Integer, ModType Rational Integer)
divIMod Rational
x Integer
m = Rational
-> Rational
-> (DivIType Rational Rational, ModType Rational Rational)
forall t1 t2.
CanDivIMod t1 t2 =>
t1 -> t2 -> (DivIType t1 t2, ModType t1 t2)
divIMod Rational
x (Integer -> Rational
forall t. CanBeRational t => t -> Rational
rational Integer
m)
instance CanDivIMod Rational Int where
type DivIType Rational Int = Integer
divIMod :: Rational -> Int -> (DivIType Rational Int, ModType Rational Int)
divIMod Rational
x Int
m = Rational
-> Rational
-> (DivIType Rational Rational, ModType Rational Rational)
forall t1 t2.
CanDivIMod t1 t2 =>
t1 -> t2 -> (DivIType t1 t2, ModType t1 t2)
divIMod Rational
x (Int -> Rational
forall t. CanBeRational t => t -> Rational
rational Int
m)
instance CanDivIMod Integer Rational where
type ModType Integer Rational = Rational
type DivIType Integer Rational = Integer
divIMod :: Integer
-> Rational
-> (DivIType Integer Rational, ModType Integer Rational)
divIMod Integer
x Rational
m = Rational
-> Rational
-> (DivIType Rational Rational, ModType Rational Rational)
forall t1 t2.
CanDivIMod t1 t2 =>
t1 -> t2 -> (DivIType t1 t2, ModType t1 t2)
divIMod (Integer -> Rational
forall t. CanBeRational t => t -> Rational
rational Integer
x) Rational
m
instance CanDivIMod Int Rational where
type ModType Int Rational = Rational
type DivIType Int Rational = Integer
divIMod :: Int -> Rational -> (DivIType Int Rational, ModType Int Rational)
divIMod Int
x Rational
m = Rational
-> Rational
-> (DivIType Rational Rational, ModType Rational Rational)
forall t1 t2.
CanDivIMod t1 t2 =>
t1 -> t2 -> (DivIType t1 t2, ModType t1 t2)
divIMod (Int -> Rational
forall t. CanBeRational t => t -> Rational
rational Int
x) Rational
m
instance CanDivIMod Double Double where
type DivIType Double Double = Integer
divIMod :: Double -> Double -> (DivIType Double Double, ModType Double Double)
divIMod = Double -> Double -> (DivIType Double Double, ModType Double Double)
forall a b. (Real a, Integral b) => a -> a -> (b, a)
divMod'
instance CanDivIMod Double Integer where
type DivIType Double Integer = Integer
divIMod :: Double
-> Integer -> (DivIType Double Integer, ModType Double Integer)
divIMod Double
x Integer
m = Double -> Double -> (DivIType Double Double, ModType Double Double)
forall t1 t2.
CanDivIMod t1 t2 =>
t1 -> t2 -> (DivIType t1 t2, ModType t1 t2)
divIMod Double
x (Integer -> Double
forall t. CanBeDouble t => t -> Double
double Integer
m)
specCanDivIMod ::
_ => T t -> Spec
specCanDivIMod :: T t -> Spec
specCanDivIMod (T String
typeName :: T t) =
String -> Spec -> Spec
forall a. HasCallStack => String -> SpecWith a -> SpecWith a
describe (String -> String -> String -> String
forall r. PrintfType r => String -> r
printf String
"CanDivMod %s %s" String
typeName String
typeName) (Spec -> Spec) -> Spec -> Spec
forall a b. (a -> b) -> a -> b
$ do
String -> Property -> SpecWith (Arg Property)
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"holds 0 <= x `mod` m < m" (Property -> SpecWith (Arg Property))
-> Property -> SpecWith (Arg Property)
forall a b. (a -> b) -> a -> b
$ do
(t -> t -> Property) -> Property
forall prop. Testable prop => prop -> Property
property ((t -> t -> Property) -> Property)
-> (t -> t -> Property) -> Property
forall a b. (a -> b) -> a -> b
$ \ (t
x :: t) (t
m :: t) ->
t -> Bool
forall t. CanTestFinite t => t -> Bool
isFinite t
x Bool -> Bool -> AndOrType Bool Bool
forall a b. CanAndOrAsymmetric a b => a -> b -> AndOrType a b
&& t
m t -> Integer -> Bool
forall a b. HasOrderCertainlyAsymmetric a b => a -> b -> Bool
!>! Integer
0 Bool -> Property -> Property
forall prop. Testable prop => Bool -> prop -> Property
==>
let xm :: ModType t t
xm = t
x t -> t -> ModType t t
forall t1 t2. CanDivIMod t1 t2 => t1 -> t2 -> ModType t1 t2
`mod` t
m in
(Integer
0 Integer -> ModType t t -> Property
forall a b.
(HasOrderCertainlyAsymmetric a b, Show a, Show b) =>
a -> b -> Property
?<=?$ ModType t t
xm) Property -> Property -> Property
forall prop1 prop2.
(Testable prop1, Testable prop2) =>
prop1 -> prop2 -> Property
.&&. (ModType t t
xm ModType t t -> t -> Property
forall a b.
(HasOrderCertainlyAsymmetric a b, Show a, Show b) =>
a -> b -> Property
?<?$ t
m)
String -> Property -> SpecWith (Arg Property)
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"holds x == (x `div'` m)*m + (x `mod` m)" (Property -> SpecWith (Arg Property))
-> Property -> SpecWith (Arg Property)
forall a b. (a -> b) -> a -> b
$ do
(t -> t -> Property) -> Property
forall prop. Testable prop => prop -> Property
property ((t -> t -> Property) -> Property)
-> (t -> t -> Property) -> Property
forall a b. (a -> b) -> a -> b
$ \ (t
x :: t) (t
m :: t) ->
t -> Bool
forall t. CanTestFinite t => t -> Bool
isFinite t
x Bool -> Bool -> AndOrType Bool Bool
forall a b. CanAndOrAsymmetric a b => a -> b -> AndOrType a b
&& t
m t -> Integer -> Bool
forall a b. HasOrderCertainlyAsymmetric a b => a -> b -> Bool
!>! Integer
0 Bool -> Property -> Property
forall prop. Testable prop => Bool -> prop -> Property
==>
let (DivIType t t
d,ModType t t
xm) = t -> t -> (DivIType t t, ModType t t)
forall t1 t2.
CanDivIMod t1 t2 =>
t1 -> t2 -> (DivIType t1 t2, ModType t1 t2)
divIMod t
x t
m in
(t
x t -> AddType (MulType (DivIType t t) t) (ModType t t) -> Property
forall a b.
(HasEqCertainlyAsymmetric a b, Show a, Show b) =>
a -> b -> Property
?==?$ (DivIType t t
dDivIType t t -> t -> MulType (DivIType t t) t
forall t1 t2. CanMulAsymmetric t1 t2 => t1 -> t2 -> MulType t1 t2
*t
m MulType (DivIType t t) t
-> ModType t t -> AddType (MulType (DivIType t t) t) (ModType t t)
forall t1 t2. CanAddAsymmetric t1 t2 => t1 -> t2 -> AddType t1 t2
+ ModType t t
xm))
where
(?<=?$) :: (HasOrderCertainlyAsymmetric a b, Show a, Show b) => a -> b -> Property
?<=?$ :: a -> b -> Property
(?<=?$) = String -> (a -> b -> Bool) -> a -> b -> Property
forall prop a b.
(Testable prop, Show a, Show b) =>
String -> (a -> b -> prop) -> a -> b -> Property
printArgsIfFails2 String
"?<=?" a -> b -> Bool
forall a b. HasOrderCertainlyAsymmetric a b => a -> b -> Bool
(?<=?)
(?<?$) :: (HasOrderCertainlyAsymmetric a b, Show a, Show b) => a -> b -> Property
?<?$ :: a -> b -> Property
(?<?$) = String -> (a -> b -> Bool) -> a -> b -> Property
forall prop a b.
(Testable prop, Show a, Show b) =>
String -> (a -> b -> prop) -> a -> b -> Property
printArgsIfFails2 String
"?<?" a -> b -> Bool
forall a b. HasOrderCertainlyAsymmetric a b => a -> b -> Bool
(?<?)
(?==?$) :: (HasEqCertainlyAsymmetric a b, Show a, Show b) => a -> b -> Property
?==?$ :: a -> b -> Property
(?==?$) = String -> (a -> b -> Bool) -> a -> b -> Property
forall prop a b.
(Testable prop, Show a, Show b) =>
String -> (a -> b -> prop) -> a -> b -> Property
printArgsIfFails2 String
"?==?" a -> b -> Bool
forall a b. HasEqCertainlyAsymmetric a b => a -> b -> Bool
(?==?)
class CanRound t where
type RoundType t
type RoundType t = Integer
properFraction :: t -> (RoundType t, t)
default properFraction :: (P.RealFrac t, RoundType t ~ Integer) => t -> (RoundType t, t)
properFraction = t -> (RoundType t, t)
forall a b. (RealFrac a, Integral b) => a -> (b, a)
P.properFraction
truncate :: t -> RoundType t
truncate = (RoundType t, t) -> RoundType t
forall a b. (a, b) -> a
fst ((RoundType t, t) -> RoundType t)
-> (t -> (RoundType t, t)) -> t -> RoundType t
forall b c a. (b -> c) -> (a -> b) -> a -> c
. t -> (RoundType t, t)
forall t. CanRound t => t -> (RoundType t, t)
properFraction
round :: t -> RoundType t
default round :: (HasOrderCertainly t Rational, RoundType t ~ Integer) => t -> RoundType t
round t
x
| -Rational
0.5 Rational -> t -> Bool
forall a b. HasOrderCertainlyAsymmetric a b => a -> b -> Bool
!<! t
r Bool -> Bool -> AndOrType Bool Bool
forall a b. CanAndOrAsymmetric a b => a -> b -> AndOrType a b
&& t
r t -> Rational -> Bool
forall a b. HasOrderCertainlyAsymmetric a b => a -> b -> Bool
!<! Rational
0.5 = Integer
RoundType t
n
| t
r t -> Rational -> Bool
forall a b. HasOrderCertainlyAsymmetric a b => a -> b -> Bool
!<! -Rational
0.5 = Integer
n Integer -> Integer -> SubType Integer Integer
forall t1 t2. CanSub t1 t2 => t1 -> t2 -> SubType t1 t2
- Integer
1
| t
r t -> Rational -> Bool
forall a b. HasOrderCertainlyAsymmetric a b => a -> b -> Bool
!>! Rational
0.5 = Integer
n Integer -> Integer -> AddType Integer Integer
forall t1 t2. CanAddAsymmetric t1 t2 => t1 -> t2 -> AddType t1 t2
+ Integer
1
| Integer -> Bool
forall a. Integral a => a -> Bool
even Integer
n = Integer
RoundType t
n
| t
r t -> Rational -> Bool
forall a b. HasOrderCertainlyAsymmetric a b => a -> b -> Bool
!<! Rational
0.0 = Integer
n Integer -> Integer -> SubType Integer Integer
forall t1 t2. CanSub t1 t2 => t1 -> t2 -> SubType t1 t2
- Integer
1
| t
r t -> Rational -> Bool
forall a b. HasOrderCertainlyAsymmetric a b => a -> b -> Bool
!>! Rational
0.0 = Integer
n Integer -> Integer -> AddType Integer Integer
forall t1 t2. CanAddAsymmetric t1 t2 => t1 -> t2 -> AddType t1 t2
+ Integer
1
| Bool
otherwise = String -> Integer
forall a. HasCallStack => String -> a
error String
"round default defn: Bad value"
where
(Integer
n,t
r) = t -> (RoundType t, t)
forall t. CanRound t => t -> (RoundType t, t)
properFraction t
x
ceiling :: t -> RoundType t
default ceiling :: (CanTestPosNeg t, RoundType t ~ Integer) => t -> RoundType t
ceiling t
x
| t -> Bool
forall t. CanTestPosNeg t => t -> Bool
isCertainlyPositive t
r = Integer
n Integer -> Integer -> AddType Integer Integer
forall t1 t2. CanAddAsymmetric t1 t2 => t1 -> t2 -> AddType t1 t2
+ Integer
1
| Bool
otherwise = Integer
RoundType t
n
where
(Integer
n,t
r) = t -> (RoundType t, t)
forall t. CanRound t => t -> (RoundType t, t)
properFraction t
x
floor :: t -> RoundType t
default floor :: (CanTestPosNeg t, RoundType t ~ Integer) => t -> RoundType t
floor t
x
| t -> Bool
forall t. CanTestPosNeg t => t -> Bool
isCertainlyNegative t
r = Integer
n Integer -> Integer -> SubType Integer Integer
forall t1 t2. CanSub t1 t2 => t1 -> t2 -> SubType t1 t2
- Integer
1
| Bool
otherwise = Integer
RoundType t
n
where
(Integer
n,t
r) = t -> (RoundType t, t)
forall t. CanRound t => t -> (RoundType t, t)
properFraction t
x
instance CanRound Rational
instance CanRound Double where
round :: Double -> RoundType Double
round = Double -> RoundType Double
forall a b. (RealFrac a, Integral b) => a -> b
P.round
ceiling :: Double -> RoundType Double
ceiling = Double -> RoundType Double
forall a b. (RealFrac a, Integral b) => a -> b
P.ceiling
floor :: Double -> RoundType Double
floor = Double -> RoundType Double
forall a b. (RealFrac a, Integral b) => a -> b
P.floor
specCanRound ::
_ => T t -> Spec
specCanRound :: T t -> Spec
specCanRound (T String
typeName :: T t) =
String -> Spec -> Spec
forall a. HasCallStack => String -> SpecWith a -> SpecWith a
describe (String -> String -> String
forall r. PrintfType r => String -> r
printf String
"CanRound %s" String
typeName) (Spec -> Spec) -> Spec -> Spec
forall a b. (a -> b) -> a -> b
$ do
String -> Property -> SpecWith (Arg Property)
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"holds floor x <= x <= ceiling x" (Property -> SpecWith (Arg Property))
-> Property -> SpecWith (Arg Property)
forall a b. (a -> b) -> a -> b
$ do
(t -> Property) -> Property
forall prop. Testable prop => prop -> Property
property ((t -> Property) -> Property) -> (t -> Property) -> Property
forall a b. (a -> b) -> a -> b
$ \ (t
x :: t) ->
t -> Bool
forall t. CanTestFinite t => t -> Bool
isFinite t
x Bool -> Property -> Property
forall prop. Testable prop => Bool -> prop -> Property
==>
(t -> RoundType t
forall t. CanRound t => t -> RoundType t
floor t
x RoundType t -> t -> Property
forall a b.
(HasOrderCertainlyAsymmetric a b, Show a, Show b) =>
a -> b -> Property
?<=?$ t
x) Property -> Property -> Property
forall prop1 prop2.
(Testable prop1, Testable prop2) =>
prop1 -> prop2 -> Property
.&&. (t
x t -> RoundType t -> Property
forall a b.
(HasOrderCertainlyAsymmetric a b, Show a, Show b) =>
a -> b -> Property
?<=?$ t -> RoundType t
forall t. CanRound t => t -> RoundType t
ceiling t
x)
String -> Property -> SpecWith (Arg Property)
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"holds floor x <= round x <= ceiling x" (Property -> SpecWith (Arg Property))
-> Property -> SpecWith (Arg Property)
forall a b. (a -> b) -> a -> b
$ do
(t -> Property) -> Property
forall prop. Testable prop => prop -> Property
property ((t -> Property) -> Property) -> (t -> Property) -> Property
forall a b. (a -> b) -> a -> b
$ \ (t
x :: t) ->
t -> Bool
forall t. CanTestFinite t => t -> Bool
isFinite t
x Bool -> Property -> Property
forall prop. Testable prop => Bool -> prop -> Property
==>
(t -> RoundType t
forall t. CanRound t => t -> RoundType t
floor t
x RoundType t -> RoundType t -> Property
forall a b.
(HasOrderCertainlyAsymmetric a b, Show a, Show b) =>
a -> b -> Property
!<=!$ t -> RoundType t
forall t. CanRound t => t -> RoundType t
round t
x) Property -> Property -> Property
forall prop1 prop2.
(Testable prop1, Testable prop2) =>
prop1 -> prop2 -> Property
.&&. (t -> RoundType t
forall t. CanRound t => t -> RoundType t
round t
x RoundType t -> RoundType t -> Property
forall a b.
(HasOrderCertainlyAsymmetric a b, Show a, Show b) =>
a -> b -> Property
!<=!$ t -> RoundType t
forall t. CanRound t => t -> RoundType t
ceiling t
x)
String -> Property -> SpecWith (Arg Property)
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"0 <= ceiling x - floor x <= 1" (Property -> SpecWith (Arg Property))
-> Property -> SpecWith (Arg Property)
forall a b. (a -> b) -> a -> b
$ do
(t -> Property) -> Property
forall prop. Testable prop => prop -> Property
property ((t -> Property) -> Property) -> (t -> Property) -> Property
forall a b. (a -> b) -> a -> b
$ \ (t
x :: t) ->
t -> Bool
forall t. CanTestFinite t => t -> Bool
isFinite t
x Bool -> Property -> Property
forall prop. Testable prop => Bool -> prop -> Property
==>
let diffCeilingFloorX :: SubType (RoundType t) (RoundType t)
diffCeilingFloorX = t -> RoundType t
forall t. CanRound t => t -> RoundType t
ceiling t
x RoundType t -> RoundType t -> SubType (RoundType t) (RoundType t)
forall t1 t2. CanSub t1 t2 => t1 -> t2 -> SubType t1 t2
- t -> RoundType t
forall t. CanRound t => t -> RoundType t
floor t
x in
(Integer
0 Integer -> SubType (RoundType t) (RoundType t) -> Bool
forall a b. HasOrderCertainlyAsymmetric a b => a -> b -> Bool
?<=? SubType (RoundType t) (RoundType t)
diffCeilingFloorX) Bool -> Bool -> Property
forall prop1 prop2.
(Testable prop1, Testable prop2) =>
prop1 -> prop2 -> Property
.&&. (SubType (RoundType t) (RoundType t)
diffCeilingFloorX SubType (RoundType t) (RoundType t) -> Integer -> Bool
forall a b. HasOrderCertainlyAsymmetric a b => a -> b -> Bool
?<=? Integer
1)
String -> Property -> SpecWith (Arg Property)
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"holds floor x = round x = ceiling x for integers" (Property -> SpecWith (Arg Property))
-> Property -> SpecWith (Arg Property)
forall a b. (a -> b) -> a -> b
$ do
(Integer -> Property) -> Property
forall prop. Testable prop => prop -> Property
property ((Integer -> Property) -> Property)
-> (Integer -> Property) -> Property
forall a b. (a -> b) -> a -> b
$ \ (Integer
xi :: Integer) ->
let x :: t
x = Integer -> t
forall t1 t2. ConvertibleExactly t1 t2 => t1 -> t2
convertExactly Integer
xi :: t in
(t -> RoundType t
forall t. CanRound t => t -> RoundType t
floor t
x RoundType t -> RoundType t -> Property
forall a b.
(HasEqCertainlyAsymmetric a b, Show a, Show b) =>
a -> b -> Property
!==!$ t -> RoundType t
forall t. CanRound t => t -> RoundType t
round t
x) Property -> Property -> Property
forall prop1 prop2.
(Testable prop1, Testable prop2) =>
prop1 -> prop2 -> Property
.&&. (t -> RoundType t
forall t. CanRound t => t -> RoundType t
round t
x RoundType t -> RoundType t -> Property
forall a b.
(HasEqCertainlyAsymmetric a b, Show a, Show b) =>
a -> b -> Property
!==!$ t -> RoundType t
forall t. CanRound t => t -> RoundType t
ceiling t
x)
where
(?<=?$) :: (HasOrderCertainlyAsymmetric a b, Show a, Show b) => a -> b -> Property
?<=?$ :: a -> b -> Property
(?<=?$) = String -> (a -> b -> Bool) -> a -> b -> Property
forall prop a b.
(Testable prop, Show a, Show b) =>
String -> (a -> b -> prop) -> a -> b -> Property
printArgsIfFails2 String
"?<=?" a -> b -> Bool
forall a b. HasOrderCertainlyAsymmetric a b => a -> b -> Bool
(?<=?)
(!<=!$) :: (HasOrderCertainlyAsymmetric a b, Show a, Show b) => a -> b -> Property
!<=!$ :: a -> b -> Property
(!<=!$) = String -> (a -> b -> Bool) -> a -> b -> Property
forall prop a b.
(Testable prop, Show a, Show b) =>
String -> (a -> b -> prop) -> a -> b -> Property
printArgsIfFails2 String
"!<=!" a -> b -> Bool
forall a b. HasOrderCertainlyAsymmetric a b => a -> b -> Bool
(!<=!)
(!==!$) :: (HasEqCertainlyAsymmetric a b, Show a, Show b) => a -> b -> Property
!==!$ :: a -> b -> Property
(!==!$) = String -> (a -> b -> Bool) -> a -> b -> Property
forall prop a b.
(Testable prop, Show a, Show b) =>
String -> (a -> b -> prop) -> a -> b -> Property
printArgsIfFails2 String
"!==!" a -> b -> Bool
forall a b. HasEqCertainlyAsymmetric a b => a -> b -> Bool
(!==!)
class HasIntegerBounds t where
integerBounds :: t -> (Integer, Integer)
default integerBounds :: (CanRound t, RoundType t ~ Integer) => t -> (Integer, Integer)
integerBounds t
x = (t -> RoundType t
forall t. CanRound t => t -> RoundType t
floor t
x, t -> RoundType t
forall t. CanRound t => t -> RoundType t
ceiling t
x)
instance HasIntegerBounds Rational
instance HasIntegerBounds Double
instance HasIntegerBounds Integer where
integerBounds :: Integer -> (Integer, Integer)
integerBounds Integer
n = (Integer
n,Integer
n)
instance HasIntegerBounds Int where
integerBounds :: Int -> (Integer, Integer)
integerBounds Int
n = (Integer
n',Integer
n') where n' :: Integer
n' = Int -> Integer
forall t. CanBeInteger t => t -> Integer
integer Int
n
specHasIntegerBounds ::
_ => T t -> Spec
specHasIntegerBounds :: T t -> Spec
specHasIntegerBounds (T String
typeName :: T t) =
String -> Spec -> Spec
forall a. HasCallStack => String -> SpecWith a -> SpecWith a
describe (String -> String -> String
forall r. PrintfType r => String -> r
printf String
"HasIntegerBounds %s" String
typeName) (Spec -> Spec) -> Spec -> Spec
forall a b. (a -> b) -> a -> b
$ do
String -> Property -> SpecWith (Arg Property)
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"holds l <= x <= r" (Property -> SpecWith (Arg Property))
-> Property -> SpecWith (Arg Property)
forall a b. (a -> b) -> a -> b
$ do
(t -> Property) -> Property
forall prop. Testable prop => prop -> Property
property ((t -> Property) -> Property) -> (t -> Property) -> Property
forall a b. (a -> b) -> a -> b
$ \ (t
x :: t) ->
t -> Bool
forall t. CanTestFinite t => t -> Bool
isFinite t
x Bool -> Property -> Property
forall prop. Testable prop => Bool -> prop -> Property
==>
let (Integer
l,Integer
r) = t -> (Integer, Integer)
forall t. HasIntegerBounds t => t -> (Integer, Integer)
integerBounds t
x in
(Integer
l Integer -> t -> Property
forall a b.
(HasOrderCertainlyAsymmetric a b, Show a, Show b) =>
a -> b -> Property
?<=?$ t
x) Property -> Property -> Property
forall prop1 prop2.
(Testable prop1, Testable prop2) =>
prop1 -> prop2 -> Property
.&&. (t
x t -> Integer -> Property
forall a b.
(HasOrderCertainlyAsymmetric a b, Show a, Show b) =>
a -> b -> Property
?<=?$ Integer
r)
where
(?<=?$) :: (HasOrderCertainlyAsymmetric a b, Show a, Show b) => a -> b -> Property
?<=?$ :: a -> b -> Property
(?<=?$) = String -> (a -> b -> Bool) -> a -> b -> Property
forall prop a b.
(Testable prop, Show a, Show b) =>
String -> (a -> b -> prop) -> a -> b -> Property
printArgsIfFails2 String
"?<=?" a -> b -> Bool
forall a b. HasOrderCertainlyAsymmetric a b => a -> b -> Bool
(?<=?)