module Math.NumberTheory.Canon.Additive (
crAdd,
crSubtract,
crAddR,
crSubtractR,
crApplyAdtvOpt,
crApplyAdtvOptConv,
crApplyAdtvOptR,
crQuotRem
)
where
import Math.NumberTheory.Canon.Internals
import Math.NumberTheory.Canon.AurifCyclo (crCycloAurifApply, CycloMap)
crAdd, crSubtract, crAddR, crSubtractR :: CR_ -> CR_ -> CycloMap -> (CR_, CycloMap)
crAdd = crApplyAdtvOpt True
crSubtract = crApplyAdtvOpt False
crAddR = crApplyAdtvOptR True
crSubtractR = crApplyAdtvOptR False
crApplyAdtvOptR :: Bool -> CR_ -> CR_ -> CycloMap -> (CR_, CycloMap)
crApplyAdtvOptR _ x PZero m = (x, m)
crApplyAdtvOptR True PZero y m = (y, m)
crApplyAdtvOptR False PZero y m = (crNegate y, m)
crApplyAdtvOptR b x y m = (crDivRational n d, m')
where (nx, dx) = crSplit x
(ny, dy) = crSplit y
nf1 = crMult nx dy
nf2 = crMult ny dx
ngcd = crGCD nf1 nf2
nf1r = crDivStrict nf1 ngcd
nf2r = crDivStrict nf2 ngcd
(nf, m') = crApplyAdtvOpt b nf1r nf2r m
n = crMult ngcd nf
d = crMult dx dy
crApplyAdtvOpt :: Bool -> CR_ -> CR_ -> CycloMap -> (CR_, CycloMap)
crApplyAdtvOpt _ x PZero m = (x, m)
crApplyAdtvOpt True PZero y m = (y, m)
crApplyAdtvOpt False PZero y m = (crNegate y, m)
crApplyAdtvOpt b x y m = (crMult gcd' r, m')
where gcd' = crGCD x y
xres = crDivStrict x gcd'
yres = crDivStrict y gcd'
(r, m') = crApplyAdtvOptConv b xres yres m
logThreshold :: Double
logThreshold = 10 * (log 10)
crApplyAdtvOptConv :: Bool -> CR_ -> CR_ -> CycloMap -> (CR_, CycloMap)
crApplyAdtvOptConv b x y m
| gi < 2 || mL <= logThreshold
= (fst $ crSimpleApply op x y, m)
| crPositive x = if crPositive y then crCycloAurifApply b ax ay g gi m
else crCycloAurifApply (not b) ax ay g gi m
| (crNegative y) && b = (crNegate c1, m1)
| (crNegative y) && not b = crCycloAurifApply b ay ax g gi m
| b = crCycloAurifApply (not b) ay ax g gi m
| otherwise = (crNegate c2, m2)
where op = if b then (+) else (-)
(ax, ay) = (crAbs x, crAbs y)
gi = gcd (crMaxRoot ax) (crMaxRoot ay)
g = fst $ crFromI $ fromIntegral gi
mL = max (crLogDouble ax) (crLogDouble ay)
(c1, m1) = crCycloAurifApply b ax ay g gi m
(c2, m2) = crCycloAurifApply (not b) ax ay g gi m
crQuotRem :: CR_ -> CR_ -> CycloMap -> ((CR_, CR_), CycloMap)
crQuotRem x y m = case (crDiv x y) of
Left _ -> ((q, md), m')
Right quotient -> ((quotient, cr0), m)
where md = fst $ crMod x y
q = crDivStrict d y
(d, m') = crSubtract x md m