@@ -13,7 +13,7 @@ import Statistics # for _mean_promote
1313import Random: Random, AbstractRNG, SamplerType, rand!
1414
1515import Base. Checked: checked_neg, checked_abs, checked_add, checked_sub, checked_mul,
16- checked_div, checked_fld, checked_cld
16+ checked_div, checked_fld, checked_cld, checked_rem, checked_mod
1717
1818using Base: @pure
1919
@@ -38,10 +38,10 @@ export
3838# Functions
3939 scaledual,
4040 wrapping_neg, wrapping_abs, wrapping_add, wrapping_sub, wrapping_mul,
41- wrapping_fdiv, wrapping_div, wrapping_fld, wrapping_cld,
41+ wrapping_div, wrapping_fld, wrapping_cld, wrapping_rem, wrapping_mod ,
4242 saturating_neg, saturating_abs, saturating_add, saturating_sub, saturating_mul,
43- saturating_fdiv, saturating_div, saturating_fld, saturating_cld,
44- checked_fdiv
43+ saturating_div, saturating_fld, saturating_cld, saturating_rem, saturating_mod ,
44+ wrapping_fdiv, saturating_fdiv, checked_fdiv
4545
4646include (" utilities.jl" )
4747
@@ -64,6 +64,12 @@ wrapping_mul(x::Real, ::Type{X}) where {X <: FixedPoint} = x % X
6464saturating_mul (x:: Real , :: Type{X} ) where {X <: FixedPoint } = clamp (x, X)
6565checked_mul (x:: Real , :: Type{X} ) where {X <: FixedPoint } = _convert (X, x)
6666
67+ # type modulus
68+ rem (x:: Real , :: Type{X} ) where {X <: FixedPoint } = _rem (x, X)
69+ wrapping_rem (x:: Real , :: Type{X} ) where {X <: FixedPoint } = _rem (x, X)
70+ saturating_rem (x:: Real , :: Type{X} ) where {X <: FixedPoint } = _rem (x, X)
71+ checked_rem (x:: Real , :: Type{X} ) where {X <: FixedPoint } = _rem (x, X)
72+
6773# constructor-style conversions
6874(:: Type{X} )(x:: X ) where {X <: FixedPoint } = x
6975(:: Type{X} )(x:: Number ) where {X <: FixedPoint } = _convert (X, x)
@@ -225,6 +231,9 @@ function wrapping_div(x::X, y::X, r::RoundingMode = RoundToZero) where {T, X <:
225231end
226232wrapping_fld (x:: X , y:: X ) where {X <: FixedPoint } = wrapping_div (x, y, RoundDown)
227233wrapping_cld (x:: X , y:: X ) where {X <: FixedPoint } = wrapping_div (x, y, RoundUp)
234+ wrapping_rem (x:: X , y:: X , r:: RoundingMode = RoundToZero) where {T, X <: FixedPoint{T} } =
235+ X (x. i - wrapping_div (x, y, r) * y. i, 0 )
236+ wrapping_mod (x:: X , y:: X ) where {X <: FixedPoint } = wrapping_rem (x, y, RoundDown)
228237
229238# saturating arithmetic
230239saturating_neg (x:: X ) where {X <: FixedPoint } = X (~ min (x. i - true , x. i), 0 )
@@ -257,6 +266,11 @@ function saturating_div(x::X, y::X, r::RoundingMode = RoundToZero) where {T, X <
257266end
258267saturating_fld (x:: X , y:: X ) where {X <: FixedPoint } = saturating_div (x, y, RoundDown)
259268saturating_cld (x:: X , y:: X ) where {X <: FixedPoint } = saturating_div (x, y, RoundUp)
269+ function saturating_rem (x:: X , y:: X , r:: RoundingMode = RoundToZero) where {T, X <: FixedPoint{T} }
270+ T <: Unsigned && r isa RoundingMode{:Up } && return zero (X)
271+ X (x. i - saturating_div (x, y, r) * y. i, 0 )
272+ end
273+ saturating_mod (x:: X , y:: X ) where {X <: FixedPoint } = saturating_rem (x, y, RoundDown)
260274
261275# checked arithmetic
262276checked_neg (x:: X ) where {X <: FixedPoint } = checked_sub (zero (X), x)
@@ -301,6 +315,16 @@ function checked_div(x::X, y::X, r::RoundingMode = RoundToZero) where {T, X <: F
301315end
302316checked_fld (x:: X , y:: X ) where {X <: FixedPoint } = checked_div (x, y, RoundDown)
303317checked_cld (x:: X , y:: X ) where {X <: FixedPoint } = checked_div (x, y, RoundUp)
318+ function checked_rem (x:: X , y:: X , r:: RoundingMode = RoundToZero) where {T, X <: FixedPoint{T} }
319+ y === zero (X) && throw (DivideError ())
320+ fx, fy = floattype (X)(x. i), floattype (X)(y. i)
321+ z = fx - round (fx / fy, r) * fy
322+ if T <: Unsigned && r isa RoundingMode{:Up }
323+ z >= zero (z) || throw_overflowerror_rem (r, x, y)
324+ end
325+ X (_unsafe_trunc (T, z), 0 )
326+ end
327+ checked_mod (x:: X , y:: X ) where {X <: FixedPoint } = checked_rem (x, y, RoundDown)
304328
305329# default arithmetic
306330const DEFAULT_ARITHMETIC = :wrapping
322346div (x:: X , y:: X , r:: RoundingMode = RoundToZero) where {X <: FixedPoint } = checked_div (x, y, r)
323347fld (x:: X , y:: X ) where {X <: FixedPoint } = checked_div (x, y, RoundDown)
324348cld (x:: X , y:: X ) where {X <: FixedPoint } = checked_div (x, y, RoundUp)
349+ rem (x:: X , y:: X ) where {X <: FixedPoint } = checked_rem (x, y, RoundToZero)
350+ rem (x:: X , y:: X , :: RoundingMode{:Down} ) where {X <: FixedPoint } = checked_rem (x, y, RoundDown)
351+ rem (x:: X , y:: X , :: RoundingMode{:Up} ) where {X <: FixedPoint } = checked_rem (x, y, RoundUp)
352+ mod (x:: X , y:: X ) where {X <: FixedPoint } = checked_rem (x, y, RoundDown)
325353
326354function minmax (x:: X , y:: X ) where {X <: FixedPoint }
327355 a, b = minmax (reinterpret (x), reinterpret (y))
@@ -377,7 +405,7 @@ for f in (:~, )
377405 $ f (x:: X ) where {X <: FixedPoint } = X ($ f (x. i), 0 )
378406 end
379407end
380- for f in (:rem , :mod , : mod1 , :min , :max )
408+ for f in (:mod1 , :min , :max )
381409 @eval begin
382410 $ f (x:: X , y:: X ) where {X <: FixedPoint } = X ($ f (x. i, y. i), 0 )
383411 end
544572 print (io, op, x, " , " , y, " ) overflowed for type " , rawtype (x))
545573 throw (OverflowError (String (take! (io))))
546574end
575+ @noinline function throw_overflowerror_rem (r:: RoundingMode , @nospecialize (x), @nospecialize (y))
576+ io = IOBuffer ()
577+ print (io, " rem(" , x, " , " , y, " , " , r, " ) overflowed for type " , typeof (x))
578+ throw (OverflowError (String (take! (io))))
579+ end
547580
548581function Random. rand (r:: AbstractRNG , :: SamplerType{X} ) where X <: FixedPoint
549582 X (rand (r, rawtype (X)), 0 )
0 commit comments