@@ -5,15 +5,15 @@ import Base: ==, <, <=, -, +, *, /, ~, isapprox,
5
5
isnan, isinf, isfinite, isinteger,
6
6
zero, oneunit, one, typemin, typemax, floatmin, floatmax, eps, reinterpret,
7
7
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,
9
9
signed, unsigned, copysign, flipsign, signbit,
10
10
length
11
11
12
12
import Statistics # for _mean_promote
13
13
import Random: Random, AbstractRNG, SamplerType, rand!
14
14
15
15
import Base. Checked: checked_neg, checked_abs, checked_add, checked_sub, checked_mul,
16
- checked_div
16
+ checked_div, checked_fld, checked_cld
17
17
18
18
using Base: @pure
19
19
38
38
# Functions
39
39
scaledual,
40
40
wrapping_neg, wrapping_abs, wrapping_add, wrapping_sub, wrapping_mul,
41
- wrapping_fdiv,
41
+ wrapping_fdiv, wrapping_div, wrapping_fld, wrapping_cld,
42
42
saturating_neg, saturating_abs, saturating_add, saturating_sub, saturating_mul,
43
- saturating_fdiv,
43
+ saturating_fdiv, saturating_div, saturating_fld, saturating_cld,
44
44
checked_fdiv
45
45
46
46
include (" utilities.jl" )
@@ -214,6 +214,17 @@ function wrapping_fdiv(x::X, y::X) where {X <: FixedPoint}
214
214
z = floattype (X)(x. i) / floattype (X)(y. i)
215
215
isfinite (z) ? z % X : zero (X)
216
216
end
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)
217
228
218
229
# saturating arithmetic
219
230
saturating_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),
235
246
saturating_fdiv (x:: X , y:: X ) where {X <: FixedPoint } =
236
247
clamp (floattype (X)(x. i) / floattype (X)(y. i), X)
237
248
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
+
238
261
# checked arithmetic
239
262
checked_neg (x:: X ) where {X <: FixedPoint } = checked_sub (zero (X), x)
240
263
function checked_abs (x:: X ) where {X <: FixedPoint }
@@ -268,6 +291,16 @@ function checked_fdiv(x::X, y::X) where {T, X <: FixedPoint{T}}
268
291
end
269
292
z % X
270
293
end
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)
271
304
272
305
# default arithmetic
273
306
const DEFAULT_ARITHMETIC = :wrapping
@@ -284,8 +317,11 @@ for (op, name) in ((:+, :add), (:-, :sub), (:*, :mul))
284
317
$ op (x:: X , y:: X ) where {X <: FixedPoint } = $ f (x, y)
285
318
end
286
319
end
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)
289
325
290
326
function minmax (x:: X , y:: X ) where {X <: FixedPoint }
291
327
a, b = minmax (reinterpret (x), reinterpret (y))
@@ -331,7 +367,7 @@ for f in (:zero, :oneunit, :one, :eps, :rawone, :rawtype, :floattype)
331
367
$ f (x:: FixedPoint ) = $ f (typeof (x))
332
368
end
333
369
end
334
- for f in (:(== ), :< , :<= , :div , :fld , : fld1 )
370
+ for f in (:(== ), :< , :<= , :fld1 )
335
371
@eval begin
336
372
$ f (x:: X , y:: X ) where {X <: FixedPoint } = $ f (x. i, y. i)
337
373
end
502
538
showtype (io, typeof (x))
503
539
throw (OverflowError (String (take! (io))))
504
540
end
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
505
547
506
548
function Random. rand (r:: AbstractRNG , :: SamplerType{X} ) where X <: FixedPoint
507
549
X (rand (r, rawtype (X)), 0 )
0 commit comments