@@ -5,15 +5,15 @@ import Base: ==, <, <=, -, +, *, /, ~, isapprox,
55 isnan, isinf, isfinite, isinteger,
66 zero, oneunit, one, typemin, typemax, floatmin, floatmax, eps, reinterpret,
77 big, rationalize, float, trunc, round, floor, ceil, bswap, clamp,
8- div, fld, rem, mod, mod1, fld1, min, max, minmax,
8+ div, fld, cld, rem, mod, mod1, fld1, min, max, minmax,
99 signed, unsigned, copysign, flipsign, signbit,
1010 length
1111
1212import 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
16+ checked_div, checked_fld, checked_cld
1717
1818using Base: @pure
1919
3838# Functions
3939 scaledual,
4040 wrapping_neg, wrapping_abs, wrapping_add, wrapping_sub, wrapping_mul,
41- wrapping_fdiv,
41+ wrapping_fdiv, wrapping_div, wrapping_fld, wrapping_cld,
4242 saturating_neg, saturating_abs, saturating_add, saturating_sub, saturating_mul,
43- saturating_fdiv,
43+ saturating_fdiv, saturating_div, saturating_fld, saturating_cld,
4444 checked_fdiv
4545
4646include (" utilities.jl" )
@@ -214,6 +214,17 @@ function wrapping_fdiv(x::X, y::X) where {X <: FixedPoint}
214214 z = floattype (X)(x. i) / floattype (X)(y. i)
215215 isfinite (z) ? z % X : zero (X)
216216end
217+ function wrapping_div (x:: X , y:: X , r:: RoundingMode = RoundToZero) where {T, X <: FixedPoint{T} }
218+ z = round (floattype (X)(x. i) / floattype (X)(y. i), r)
219+ isfinite (z) || return zero (T)
220+ if T <: Unsigned
221+ _unsafe_trunc (T, z)
222+ else
223+ z > typemax (T) ? typemin (T) : _unsafe_trunc (T, z)
224+ end
225+ end
226+ wrapping_fld (x:: X , y:: X ) where {X <: FixedPoint } = wrapping_div (x, y, RoundDown)
227+ wrapping_cld (x:: X , y:: X ) where {X <: FixedPoint } = wrapping_div (x, y, RoundUp)
217228
218229# saturating arithmetic
219230saturating_neg (x:: X ) where {X <: FixedPoint } = X (~ min (x. i - true , x. i), 0 )
@@ -235,6 +246,18 @@ saturating_mul(x::X, y::X) where {X <: FixedPoint} = clamp(float(x) * float(y),
235246saturating_fdiv (x:: X , y:: X ) where {X <: FixedPoint } =
236247 clamp (floattype (X)(x. i) / floattype (X)(y. i), X)
237248
249+ function saturating_div (x:: X , y:: X , r:: RoundingMode = RoundToZero) where {T, X <: FixedPoint{T} }
250+ z = round (floattype (X)(x. i) / floattype (X)(y. i), r)
251+ isnan (z) && return zero (T)
252+ if T <: Unsigned
253+ isfinite (z) ? _unsafe_trunc (T, z) : typemax (T)
254+ else
255+ _unsafe_trunc (T, clamp (z, typemin (T), typemax (T)))
256+ end
257+ end
258+ saturating_fld (x:: X , y:: X ) where {X <: FixedPoint } = saturating_div (x, y, RoundDown)
259+ saturating_cld (x:: X , y:: X ) where {X <: FixedPoint } = saturating_div (x, y, RoundUp)
260+
238261# checked arithmetic
239262checked_neg (x:: X ) where {X <: FixedPoint } = checked_sub (zero (X), x)
240263function checked_abs (x:: X ) where {X <: FixedPoint }
@@ -268,6 +291,16 @@ function checked_fdiv(x::X, y::X) where {T, X <: FixedPoint{T}}
268291 end
269292 z % X
270293end
294+ function checked_div (x:: X , y:: X , r:: RoundingMode = RoundToZero) where {T, X <: FixedPoint{T} }
295+ y === zero (X) && throw (DivideError ())
296+ z = round (floattype (X)(x. i) / floattype (X)(y. i), r)
297+ if T <: Signed
298+ z <= typemax (T) || throw_overflowerror_div (r, x, y)
299+ end
300+ _unsafe_trunc (T, z)
301+ end
302+ checked_fld (x:: X , y:: X ) where {X <: FixedPoint } = checked_div (x, y, RoundDown)
303+ checked_cld (x:: X , y:: X ) where {X <: FixedPoint } = checked_div (x, y, RoundUp)
271304
272305# default arithmetic
273306const DEFAULT_ARITHMETIC = :wrapping
@@ -284,8 +317,11 @@ for (op, name) in ((:+, :add), (:-, :sub), (:*, :mul))
284317 $ op (x:: X , y:: X ) where {X <: FixedPoint } = $ f (x, y)
285318 end
286319end
287- / (x:: X , y:: X ) where {X <: FixedPoint } = checked_fdiv (x, y) # force checked arithmetic
288-
320+ # force checked arithmetic
321+ / (x:: X , y:: X ) where {X <: FixedPoint } = checked_fdiv (x, y)
322+ div (x:: X , y:: X , r:: RoundingMode = RoundToZero) where {X <: FixedPoint } = checked_div (x, y, r)
323+ fld (x:: X , y:: X ) where {X <: FixedPoint } = checked_div (x, y, RoundDown)
324+ cld (x:: X , y:: X ) where {X <: FixedPoint } = checked_div (x, y, RoundUp)
289325
290326function minmax (x:: X , y:: X ) where {X <: FixedPoint }
291327 a, b = minmax (reinterpret (x), reinterpret (y))
@@ -331,7 +367,7 @@ for f in (:zero, :oneunit, :one, :eps, :rawone, :rawtype, :floattype)
331367 $ f (x:: FixedPoint ) = $ f (typeof (x))
332368 end
333369end
334- for f in (:(== ), :< , :<= , :div , :fld , : fld1 )
370+ for f in (:(== ), :< , :<= , :fld1 )
335371 @eval begin
336372 $ f (x:: X , y:: X ) where {X <: FixedPoint } = $ f (x. i, y. i)
337373 end
502538 showtype (io, typeof (x))
503539 throw (OverflowError (String (take! (io))))
504540end
541+ @noinline function throw_overflowerror_div (r:: RoundingMode , @nospecialize (x), @nospecialize (y))
542+ io = IOBuffer ()
543+ op = r === RoundUp ? " cld(" : r === RoundDown ? " fld(" : " div("
544+ print (io, op, x, " , " , y, " ) overflowed for type " , rawtype (x))
545+ throw (OverflowError (String (take! (io))))
546+ end
505547
506548function Random. rand (r:: AbstractRNG , :: SamplerType{X} ) where X <: FixedPoint
507549 X (rand (r, rawtype (X)), 0 )
0 commit comments