@@ -11,9 +11,6 @@ import Base: ==, <, <=, -, +, *, /, ~, isapprox,
11
11
12
12
import Random: Random, AbstractRNG, SamplerType, rand!
13
13
14
- import Base. Checked: checked_neg, checked_abs, checked_add, checked_sub, checked_mul,
15
- checked_div, checked_fld, checked_cld, checked_rem, checked_mod
16
-
17
14
using Base: @pure
18
15
19
16
"""
@@ -35,14 +32,11 @@ export
35
32
# "special" typealiases
36
33
# Q and N typealiases are exported in separate source files
37
34
# Functions
38
- scaledual,
39
- wrapping_neg, wrapping_abs, wrapping_add, wrapping_sub, wrapping_mul,
40
- wrapping_div, wrapping_fld, wrapping_cld, wrapping_rem, wrapping_mod,
41
- saturating_neg, saturating_abs, saturating_add, saturating_sub, saturating_mul,
42
- saturating_div, saturating_fld, saturating_cld, saturating_rem, saturating_mod,
43
- wrapping_fdiv, saturating_fdiv, checked_fdiv
35
+ scaledual
44
36
45
37
include (" utilities.jl" )
38
+ using . Utilities
39
+ import . Utilities: floattype, rawone, nbitsfrac, rawtype, signbits, nbitsint, scaledual
46
40
47
41
# reinterpretation
48
42
reinterpret (x:: FixedPoint ) = x. i
@@ -57,18 +51,6 @@ rawtype(::Type{X}) where {T, X <: FixedPoint{T}} = T
57
51
signbits (:: Type{X} ) where {T, X <: FixedPoint{T} } = T <: Unsigned ? 0 : 1
58
52
nbitsint (:: Type{X} ) where {X <: FixedPoint } = bitwidth (X) - nbitsfrac (X) - signbits (X)
59
53
60
- # construction using the (approximate) intended value, i.e., N0f8
61
- * (x:: Real , :: Type{X} ) where {X <: FixedPoint } = _convert (X, x)
62
- wrapping_mul (x:: Real , :: Type{X} ) where {X <: FixedPoint } = x % X
63
- saturating_mul (x:: Real , :: Type{X} ) where {X <: FixedPoint } = clamp (x, X)
64
- checked_mul (x:: Real , :: Type{X} ) where {X <: FixedPoint } = _convert (X, x)
65
-
66
- # type modulus
67
- rem (x:: Real , :: Type{X} ) where {X <: FixedPoint } = _rem (x, X)
68
- wrapping_rem (x:: Real , :: Type{X} ) where {X <: FixedPoint } = _rem (x, X)
69
- saturating_rem (x:: Real , :: Type{X} ) where {X <: FixedPoint } = _rem (x, X)
70
- checked_rem (x:: Real , :: Type{X} ) where {X <: FixedPoint } = _rem (x, X)
71
-
72
54
# constructor-style conversions
73
55
(:: Type{X} )(x:: X ) where {X <: FixedPoint } = x
74
56
(:: Type{X} )(x:: Number ) where {X <: FixedPoint } = _convert (X, x)
@@ -139,9 +121,6 @@ zero(::Type{X}) where {X <: FixedPoint} = X(zero(rawtype(X)), 0)
139
121
oneunit (:: Type{X} ) where {X <: FixedPoint } = X (rawone (X), 0 )
140
122
one (:: Type{X} ) where {X <: FixedPoint } = oneunit (X)
141
123
142
- # for Julia v1.0, which does not fold `div_float` before inlining
143
- inv_rawone (x) = (@generated ) ? (y = 1.0 / rawone (x); :($ y)) : 1.0 / rawone (x)
144
-
145
124
# traits
146
125
eps (:: Type{X} ) where {X <: FixedPoint } = X (oneunit (rawtype (X)), 0 )
147
126
typemax (:: Type{T} ) where {T <: FixedPoint } = T (typemax (rawtype (T)), 0 )
@@ -192,164 +171,12 @@ RGB{Float32}
192
171
193
172
`RGB` itself is not a subtype of `AbstractFloat`, but unlike `RGB{N0f8}` operations with `RGB{Float32}` are not subject to integer overflow.
194
173
"""
195
- floattype (:: Type{T} ) where {T <: AbstractFloat } = T # fallback (we want a MethodError if no method producing AbstractFloat is defined)
196
- floattype (:: Type{T} ) where {T <: Union{ShortInts, Bool} } = Float32
197
- floattype (:: Type{T} ) where {T <: Integer } = Float64
198
- floattype (:: Type{T} ) where {T <: LongInts } = BigFloat
199
- floattype (:: Type{T} ) where {I <: Integer , T <: Rational{I} } = typeof (zero (I)/ oneunit (I))
200
- floattype (:: Type{<:AbstractIrrational} ) = Float64
201
174
floattype (:: Type{X} ) where {T <: ShortInts , X <: FixedPoint{T} } = Float32
202
175
floattype (:: Type{X} ) where {T <: Integer , X <: FixedPoint{T} } = Float64
203
176
floattype (:: Type{X} ) where {T <: LongInts , X <: FixedPoint{T} } = BigFloat
204
177
205
- # Non-Real types
206
- floattype (:: Type{Complex{T}} ) where T = Complex{floattype (T)}
207
- floattype (:: Type{Base.TwicePrecision{Float64}} ) = Float64 # wider would be nice, but hardware support is paramount
208
- floattype (:: Type{Base.TwicePrecision{T}} ) where T<: Union{Float16,Float32} = widen (T)
209
-
210
178
float (x:: FixedPoint ) = convert (floattype (x), x)
211
179
212
- # wrapping arithmetic
213
- wrapping_neg (x:: X ) where {X <: FixedPoint } = X (- x. i, 0 )
214
- wrapping_abs (x:: X ) where {X <: FixedPoint } = X (abs (x. i), 0 )
215
- wrapping_add (x:: X , y:: X ) where {X <: FixedPoint } = X (x. i + y. i, 0 )
216
- wrapping_sub (x:: X , y:: X ) where {X <: FixedPoint } = X (x. i - y. i, 0 )
217
- wrapping_mul (x:: X , y:: X ) where {X <: FixedPoint } = (float (x) * float (y)) % X
218
- function wrapping_fdiv (x:: X , y:: X ) where {X <: FixedPoint }
219
- z = floattype (X)(x. i) / floattype (X)(y. i)
220
- isfinite (z) ? z % X : zero (X)
221
- end
222
- function wrapping_div (x:: X , y:: X , r:: RoundingMode = RoundToZero) where {T, X <: FixedPoint{T} }
223
- z = round (floattype (X)(x. i) / floattype (X)(y. i), r)
224
- isfinite (z) || return zero (T)
225
- if T <: Unsigned
226
- _unsafe_trunc (T, z)
227
- else
228
- z > typemax (T) ? typemin (T) : _unsafe_trunc (T, z)
229
- end
230
- end
231
- wrapping_fld (x:: X , y:: X ) where {X <: FixedPoint } = wrapping_div (x, y, RoundDown)
232
- wrapping_cld (x:: X , y:: X ) where {X <: FixedPoint } = wrapping_div (x, y, RoundUp)
233
- wrapping_rem (x:: X , y:: X , r:: RoundingMode = RoundToZero) where {T, X <: FixedPoint{T} } =
234
- X (x. i - wrapping_div (x, y, r) * y. i, 0 )
235
- wrapping_mod (x:: X , y:: X ) where {X <: FixedPoint } = wrapping_rem (x, y, RoundDown)
236
-
237
- # saturating arithmetic
238
- saturating_neg (x:: X ) where {X <: FixedPoint } = X (~ min (x. i - true , x. i), 0 )
239
- saturating_neg (x:: X ) where {X <: FixedPoint{<:Unsigned} } = zero (X)
240
-
241
- saturating_abs (x:: X ) where {X <: FixedPoint } =
242
- X (ifelse (signbit (abs (x. i)), typemax (x. i), abs (x. i)), 0 )
243
-
244
- saturating_add (x:: X , y:: X ) where {X <: FixedPoint } =
245
- X (x. i + ifelse (x. i < 0 , max (y. i, typemin (x. i) - x. i), min (y. i, typemax (x. i) - x. i)), 0 )
246
- saturating_add (x:: X , y:: X ) where {X <: FixedPoint{<:Unsigned} } = X (x. i + min (~ x. i, y. i), 0 )
247
-
248
- saturating_sub (x:: X , y:: X ) where {X <: FixedPoint } =
249
- X (x. i - ifelse (x. i < 0 , min (y. i, x. i - typemin (x. i)), max (y. i, x. i - typemax (x. i))), 0 )
250
- saturating_sub (x:: X , y:: X ) where {X <: FixedPoint{<:Unsigned} } = X (x. i - min (x. i, y. i), 0 )
251
-
252
- saturating_mul (x:: X , y:: X ) where {X <: FixedPoint } = clamp (float (x) * float (y), X)
253
-
254
- saturating_fdiv (x:: X , y:: X ) where {X <: FixedPoint } =
255
- clamp (floattype (X)(x. i) / floattype (X)(y. i), X)
256
-
257
- function saturating_div (x:: X , y:: X , r:: RoundingMode = RoundToZero) where {T, X <: FixedPoint{T} }
258
- z = round (floattype (X)(x. i) / floattype (X)(y. i), r)
259
- isnan (z) && return zero (T)
260
- if T <: Unsigned
261
- isfinite (z) ? _unsafe_trunc (T, z) : typemax (T)
262
- else
263
- _unsafe_trunc (T, clamp (z, typemin (T), typemax (T)))
264
- end
265
- end
266
- saturating_fld (x:: X , y:: X ) where {X <: FixedPoint } = saturating_div (x, y, RoundDown)
267
- saturating_cld (x:: X , y:: X ) where {X <: FixedPoint } = saturating_div (x, y, RoundUp)
268
- function saturating_rem (x:: X , y:: X , r:: RoundingMode = RoundToZero) where {T, X <: FixedPoint{T} }
269
- T <: Unsigned && r isa RoundingMode{:Up } && return zero (X)
270
- X (x. i - saturating_div (x, y, r) * y. i, 0 )
271
- end
272
- saturating_mod (x:: X , y:: X ) where {X <: FixedPoint } = saturating_rem (x, y, RoundDown)
273
-
274
- # checked arithmetic
275
- checked_neg (x:: X ) where {X <: FixedPoint } = checked_sub (zero (X), x)
276
- function checked_abs (x:: X ) where {X <: FixedPoint }
277
- abs (x. i) >= 0 || throw_overflowerror_abs (x)
278
- X (abs (x. i), 0 )
279
- end
280
- function checked_add (x:: X , y:: X ) where {X <: FixedPoint }
281
- r, f = Base. Checked. add_with_overflow (x. i, y. i)
282
- z = X (r, 0 ) # store first
283
- f && throw_overflowerror (:+ , x, y)
284
- z
285
- end
286
- function checked_sub (x:: X , y:: X ) where {X <: FixedPoint }
287
- r, f = Base. Checked. sub_with_overflow (x. i, y. i)
288
- z = X (r, 0 ) # store first
289
- f && throw_overflowerror (:- , x, y)
290
- z
291
- end
292
- function checked_mul (x:: X , y:: X ) where {X <: FixedPoint }
293
- z = float (x) * float (y)
294
- typemin (X) - eps (X)/ 2 <= z < typemax (X) + eps (X)/ 2 || throw_overflowerror (:* , x, y)
295
- z % X
296
- end
297
- function checked_fdiv (x:: X , y:: X ) where {T, X <: FixedPoint{T} }
298
- y === zero (X) && throw (DivideError ())
299
- z = floattype (X)(x. i) / floattype (X)(y. i)
300
- if T <: Unsigned
301
- z < typemax (X) + eps (X)/ 2 || throw_overflowerror (:/ , x, y)
302
- else
303
- typemin (X) - eps (X)/ 2 <= z < typemax (X) + eps (X)/ 2 || throw_overflowerror (:/ , x, y)
304
- end
305
- z % X
306
- end
307
- function checked_div (x:: X , y:: X , r:: RoundingMode = RoundToZero) where {T, X <: FixedPoint{T} }
308
- y === zero (X) && throw (DivideError ())
309
- z = round (floattype (X)(x. i) / floattype (X)(y. i), r)
310
- if T <: Signed
311
- z <= typemax (T) || throw_overflowerror_div (r, x, y)
312
- end
313
- _unsafe_trunc (T, z)
314
- end
315
- checked_fld (x:: X , y:: X ) where {X <: FixedPoint } = checked_div (x, y, RoundDown)
316
- checked_cld (x:: X , y:: X ) where {X <: FixedPoint } = checked_div (x, y, RoundUp)
317
- function checked_rem (x:: X , y:: X , r:: RoundingMode = RoundToZero) where {T, X <: FixedPoint{T} }
318
- y === zero (X) && throw (DivideError ())
319
- fx, fy = floattype (X)(x. i), floattype (X)(y. i)
320
- z = fx - round (fx / fy, r) * fy
321
- if T <: Unsigned && r isa RoundingMode{:Up }
322
- z >= zero (z) || throw_overflowerror_rem (r, x, y)
323
- end
324
- X (_unsafe_trunc (T, z), 0 )
325
- end
326
- checked_mod (x:: X , y:: X ) where {X <: FixedPoint } = checked_rem (x, y, RoundDown)
327
-
328
- # default arithmetic
329
- const DEFAULT_ARITHMETIC = :wrapping
330
-
331
- for (op, name) in ((:- , :neg ), (:abs , :abs ))
332
- f = Symbol (DEFAULT_ARITHMETIC, :_ , name)
333
- @eval begin
334
- $ op (x:: X ) where {X <: FixedPoint } = $ f (x)
335
- end
336
- end
337
- for (op, name) in ((:+ , :add ), (:- , :sub ), (:* , :mul ))
338
- f = Symbol (DEFAULT_ARITHMETIC, :_ , name)
339
- @eval begin
340
- $ op (x:: X , y:: X ) where {X <: FixedPoint } = $ f (x, y)
341
- end
342
- end
343
- # force checked arithmetic
344
- / (x:: X , y:: X ) where {X <: FixedPoint } = checked_fdiv (x, y)
345
- div (x:: X , y:: X , r:: RoundingMode = RoundToZero) where {X <: FixedPoint } = checked_div (x, y, r)
346
- fld (x:: X , y:: X ) where {X <: FixedPoint } = checked_div (x, y, RoundDown)
347
- cld (x:: X , y:: X ) where {X <: FixedPoint } = checked_div (x, y, RoundUp)
348
- rem (x:: X , y:: X ) where {X <: FixedPoint } = checked_rem (x, y, RoundToZero)
349
- rem (x:: X , y:: X , :: RoundingMode{:Down} ) where {X <: FixedPoint } = checked_rem (x, y, RoundDown)
350
- rem (x:: X , y:: X , :: RoundingMode{:Up} ) where {X <: FixedPoint } = checked_rem (x, y, RoundUp)
351
- mod (x:: X , y:: X ) where {X <: FixedPoint } = checked_rem (x, y, RoundDown)
352
-
353
180
function minmax (x:: X , y:: X ) where {X <: FixedPoint }
354
181
a, b = minmax (reinterpret (x), reinterpret (y))
355
182
X (a,0 ), X (b,0 )
@@ -518,6 +345,31 @@ include("normed.jl")
518
345
include (" deprecations.jl" )
519
346
const UF = (N0f8, N6f10, N4f12, N2f14, N0f16)
520
347
348
+ include (" arithmetic/arithmetic.jl" )
349
+ using . FixedPointArithmetic
350
+ # re-export
351
+ for name in names (FixedPointArithmetic. Wrapping)
352
+ @eval export $ name
353
+ end
354
+ for name in names (FixedPointArithmetic. Saturating)
355
+ @eval export $ name
356
+ end
357
+ for name in names (FixedPointArithmetic. Checked)
358
+ @eval export $ name
359
+ end
360
+
361
+ # construction using the (approximate) intended value, i.e., N0f8
362
+ * (x:: Real , :: Type{X} ) where {X <: FixedPoint } = _convert (X, x)
363
+ Wrapping. wrapping_mul (x:: Real , :: Type{X} ) where {X <: FixedPoint } = x % X
364
+ Saturating. saturating_mul (x:: Real , :: Type{X} ) where {X <: FixedPoint } = clamp (x, X)
365
+ Checked. checked_mul (x:: Real , :: Type{X} ) where {X <: FixedPoint } = _convert (X, x)
366
+
367
+ # type modulus
368
+ rem (x:: Real , :: Type{X} ) where {X <: FixedPoint } = _rem (x, X)
369
+ Wrapping. wrapping_rem (x:: Real , :: Type{X} ) where {X<: FixedPoint } = _rem (x, X)
370
+ Saturating. saturating_rem (x:: Real , :: Type{X} ) where {X<: FixedPoint } = _rem (x, X)
371
+ Checked. checked_rem (x:: Real , :: Type{X} ) where {X<: FixedPoint } = _rem (x, X)
372
+
521
373
# Promotions
522
374
promote_rule (:: Type{X} , :: Type{Tf} ) where {X <: FixedPoint , Tf <: AbstractFloat } =
523
375
promote_type (floattype (X), Tf)
@@ -585,29 +437,6 @@ scaledual(::Type{Tdual}, x::AbstractArray{T}) where {Tdual, T <: FixedPoint} =
585
437
throw (ArgumentError (String (take! (io))))
586
438
end
587
439
588
- @noinline function throw_overflowerror (op:: Symbol , @nospecialize (x), @nospecialize (y))
589
- io = IOBuffer ()
590
- print (io, x, ' ' , op, ' ' , y, " overflowed for type " )
591
- showtype (io, typeof (x))
592
- throw (OverflowError (String (take! (io))))
593
- end
594
- @noinline function throw_overflowerror_abs (@nospecialize (x))
595
- io = IOBuffer ()
596
- print (io, " abs(" , x, " ) overflowed for type " )
597
- showtype (io, typeof (x))
598
- throw (OverflowError (String (take! (io))))
599
- end
600
- @noinline function throw_overflowerror_div (r:: RoundingMode , @nospecialize (x), @nospecialize (y))
601
- io = IOBuffer ()
602
- op = r === RoundUp ? " cld(" : r === RoundDown ? " fld(" : " div("
603
- print (io, op, x, " , " , y, " ) overflowed for type " , rawtype (x))
604
- throw (OverflowError (String (take! (io))))
605
- end
606
- @noinline function throw_overflowerror_rem (r:: RoundingMode , @nospecialize (x), @nospecialize (y))
607
- io = IOBuffer ()
608
- print (io, " rem(" , x, " , " , y, " , " , r, " ) overflowed for type " , typeof (x))
609
- throw (OverflowError (String (take! (io))))
610
- end
611
440
612
441
function Random. rand (r:: AbstractRNG , :: SamplerType{X} ) where X <: FixedPoint
613
442
X (rand (r, rawtype (X)), 0 )
0 commit comments