Skip to content

Commit d61202b

Browse files
authored
svDivide: Always use Euclidean division for unbounded integers (#802)
* Factor out {div,mod}Eucl into top-level definitions Towards #799. * svDivide: Always use Euclidean division for unbounded integers Fixes #799.
1 parent bb8746a commit d61202b

2 files changed

Lines changed: 23 additions & 7 deletions

File tree

Data/SBV/Core/Operations.hs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ import Data.SBV.Core.SizedFloats
7575

7676
import Data.Ratio
7777

78-
import Data.SBV.Utils.Numeric (RoundingMode(..), {-fp2fp,-} fpIsEqualObjectH, fpIsNormalizedH, fpMaxH, fpMinH, fpRemH, fpRoundToIntegralH, floatToWord, doubleToWord, wordToFloat, wordToDouble)
78+
import Data.SBV.Utils.Numeric (RoundingMode(..), divEucl, modEucl, {-fp2fp,-} fpIsEqualObjectH, fpIsNormalizedH, fpMaxH, fpMinH, fpRemH, fpRoundToIntegralH, floatToWord, doubleToWord, wordToFloat, wordToDouble)
7979

8080
import LibBF
8181

@@ -238,11 +238,15 @@ svSignum a
238238
z = SVal k $ Left $ mkConstCV k (0 :: Integer)
239239
i = SVal k $ Left $ mkConstCV k (1 :: Integer)
240240

241-
-- | Division.
241+
-- | Division. For integers, this behaves like 'svQuot', except that this
242+
-- ensures @'svQuot' a 0 = a@.
242243
svDivide :: SVal -> SVal -> SVal
243-
svDivide = liftSym2 (mkSymOp Quot) [rationalCheck] (/) idiv (/) (/) (/) (/)
244-
where idiv x 0 = x
245-
idiv x y = x `quot` y
244+
svDivide x y = liftSym2 (mkSymOp Quot) [rationalCheck] (/) idiv (/) (/) (/) (/) x y
245+
where isInteger = kindOf x == KUnbounded
246+
247+
idiv a 0 = a
248+
idiv a b | isInteger = a `divEucl` b
249+
| True = a `quot` b
246250

247251
-- | Divides predicate
248252
svDivides :: Integer -> SVal -> SVal
@@ -333,7 +337,7 @@ svQuot x y
333337
where
334338
isInteger = kindOf x == KUnbounded
335339

336-
quot' a b | isInteger = div a (abs b) * signum b
340+
quot' a b | isInteger = divEucl a b
337341
| True = quot a b
338342

339343
-- | Remainder: Overloaded operation whose meaning depends on the kind at which
@@ -360,7 +364,7 @@ svRem x y
360364
where
361365
isInteger = kindOf x == KUnbounded
362366

363-
rem' a b | isInteger = mod a (abs b)
367+
rem' a b | isInteger = modEucl a b
364368
| True = rem a b
365369

366370
-- | Combination of 'svQuot' and 'svRem'

Data/SBV/Utils/Numeric.hs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
module Data.SBV.Utils.Numeric (
1818
fpMaxH, fpMinH, fp2fp, fpRemH, fpRoundToIntegralH, fpIsEqualObjectH, fpCompareObjectH, fpIsNormalizedH
1919
, roundAway
20+
, divEucl, modEucl
2021
, floatToWord, wordToFloat, doubleToWord, wordToDouble
2122
, RoundingMode(..), smtRoundingMode
2223
) where
@@ -142,6 +143,17 @@ roundAway x = case properFraction x of
142143
else
143144
n + 1
144145

146+
-- | Euclidean division. @'divEucl' a b@ returns the integer @q@ satisfying the
147+
-- equations @a = (b * q) + r@ and @0 <= r < abs b@, where @'modEucl' a b = r@.
148+
divEucl :: Integral a => a -> a -> a
149+
divEucl a b = div a (abs b) * signum b
150+
151+
-- | Euclidean modular division. @'modEucl' a b@ returns the integer @r@
152+
-- satisfying the equations @a = (b * q) + r@ and @0 <= r < abs b@, where
153+
-- @'divEucl' a b = q@.
154+
modEucl :: Integral a => a -> a -> a
155+
modEucl a b = mod a (abs b)
156+
145157
-------------------------------------------------------------------------
146158
-- Reinterpreting float/double as word32/64 and back. Here, we use the
147159
-- definitions from the reinterpret-cast package:

0 commit comments

Comments
 (0)