@@ -27,13 +27,7 @@ module FixedPointDecimals
27
27
28
28
export FixedDecimal, RoundThrows
29
29
30
- import Base: reinterpret, zero, one, abs, sign, == , < , <= , + , - , / , * , div, rem, divrem,
31
- fld, mod, fldmod, fld1, mod1, fldmod1, isinteger, typemin, typemax,
32
- print, show, string, convert, parse, promote_rule, min, max,
33
- floatmin, floatmax, trunc, round, floor, ceil, eps, float, widemul, decompose
34
-
35
- const BitInteger = Union{Int8, UInt8, Int16, UInt16, Int32, UInt32, Int64,
36
- UInt64, Int128, UInt128}
30
+ using Base: decompose, BitInteger, @pure
37
31
38
32
# floats that support fma and are roughly IEEE-like
39
33
const FMAFloat = Union{Float16, Float32, Float64, BigFloat}
@@ -85,8 +79,8 @@ struct FixedDecimal{T <: Integer, f} <: Real
85
79
i:: T
86
80
87
81
# inner constructor
88
- # This function is marked as `Base. @pure`. It does not have or depend on any side-effects.
89
- Base . @pure function Base. reinterpret (:: Type{FixedDecimal{T, f}} , i:: Integer ) where {T, f}
82
+ # This function is marked as `@pure`. It does not have or depend on any side-effects.
83
+ @pure function Base. reinterpret (:: Type{FixedDecimal{T, f}} , i:: Integer ) where {T, f}
90
84
n = max_exp10 (T)
91
85
if f >= 0 && (n < 0 || f <= n)
92
86
new {T, f} (i % T)
@@ -114,22 +108,22 @@ floattype(::Type{<:FD{T}}) where {T<:Integer} = Float64
114
108
floattype (:: Type{<:FD{BigInt}} ) = BigFloat
115
109
116
110
# basic operators
117
- - (x:: FD{T, f} ) where {T, f} = reinterpret (FD{T, f}, - x. i)
118
- abs (x:: FD{T, f} ) where {T, f} = reinterpret (FD{T, f}, abs (x. i))
111
+ Base.: - (x:: FD{T, f} ) where {T, f} = reinterpret (FD{T, f}, - x. i)
112
+ Base . abs (x:: FD{T, f} ) where {T, f} = reinterpret (FD{T, f}, abs (x. i))
119
113
120
- + (x:: FD{T, f} , y:: FD{T, f} ) where {T, f} = reinterpret (FD{T, f}, x. i+ y. i)
121
- - (x:: FD{T, f} , y:: FD{T, f} ) where {T, f} = reinterpret (FD{T, f}, x. i- y. i)
114
+ Base.: + (x:: FD{T, f} , y:: FD{T, f} ) where {T, f} = reinterpret (FD{T, f}, x. i+ y. i)
115
+ Base.: - (x:: FD{T, f} , y:: FD{T, f} ) where {T, f} = reinterpret (FD{T, f}, x. i- y. i)
122
116
123
117
# wide multiplication
124
- Base . @pure function widemul (x:: FD{<:Any, f} , y:: FD{<:Any, g} ) where {f, g}
118
+ @pure function Base . widemul (x:: FD{<:Any, f} , y:: FD{<:Any, g} ) where {f, g}
125
119
i = widemul (x. i, y. i)
126
120
reinterpret (FD{typeof (i), f + g}, i)
127
121
end
128
- Base . @pure function widemul (x:: FD{T, f} , y:: Integer ) where {T, f}
122
+ @pure function Base . widemul (x:: FD{T, f} , y:: Integer ) where {T, f}
129
123
i = widemul (x. i, y)
130
124
reinterpret (FD{typeof (i), f}, i)
131
125
end
132
- Base . @pure widemul (x:: Integer , y:: FD ) = widemul (y, x)
126
+ @pure Base . widemul (x:: Integer , y:: FD ) = widemul (y, x)
133
127
134
128
"""
135
129
_round_to_even(quotient, remainder, divisor)
@@ -160,48 +154,48 @@ _round_to_even(q, r, d) = _round_to_even(promote(q, r, d)...)
160
154
# multiplication rounds to nearest even representation
161
155
# TODO : can we use floating point to speed this up? after we build a
162
156
# correctness test suite.
163
- function * (x:: FD{T, f} , y:: FD{T, f} ) where {T, f}
157
+ function Base.: * (x:: FD{T, f} , y:: FD{T, f} ) where {T, f}
164
158
powt = coefficient (FD{T, f})
165
159
quotient, remainder = fldmodinline (widemul (x. i, y. i), powt)
166
160
reinterpret (FD{T, f}, _round_to_even (quotient, remainder, powt))
167
161
end
168
162
169
163
# these functions are needed to avoid InexactError when converting from the
170
164
# integer type
171
- * (x:: Integer , y:: FD{T, f} ) where {T, f} = reinterpret (FD{T, f}, T (x * y. i))
172
- * (x:: FD{T, f} , y:: Integer ) where {T, f} = reinterpret (FD{T, f}, T (x. i * y))
165
+ Base.: * (x:: Integer , y:: FD{T, f} ) where {T, f} = reinterpret (FD{T, f}, T (x * y. i))
166
+ Base.: * (x:: FD{T, f} , y:: Integer ) where {T, f} = reinterpret (FD{T, f}, T (x. i * y))
173
167
174
- function / (x:: FD{T, f} , y:: FD{T, f} ) where {T, f}
168
+ function Base.: / (x:: FD{T, f} , y:: FD{T, f} ) where {T, f}
175
169
powt = coefficient (FD{T, f})
176
170
quotient, remainder = fldmod (widemul (x. i, powt), y. i)
177
171
reinterpret (FD{T, f}, T (_round_to_even (quotient, remainder, y. i)))
178
172
end
179
173
180
174
# These functions allow us to perform division with integers outside of the range of the
181
175
# FixedDecimal.
182
- function / (x:: Integer , y:: FD{T, f} ) where {T, f}
176
+ function Base.: / (x:: Integer , y:: FD{T, f} ) where {T, f}
183
177
powt = coefficient (FD{T, f})
184
178
powtsq = widemul (powt, powt)
185
179
quotient, remainder = fldmod (widemul (x, powtsq), y. i)
186
180
reinterpret (FD{T, f}, T (_round_to_even (quotient, remainder, y. i)))
187
181
end
188
182
189
- function / (x:: FD{T, f} , y:: Integer ) where {T, f}
183
+ function Base.: / (x:: FD{T, f} , y:: Integer ) where {T, f}
190
184
quotient, remainder = fldmod (x. i, y)
191
185
reinterpret (FD{T, f}, T (_round_to_even (quotient, remainder, y)))
192
186
end
193
187
194
188
# integerification
195
- trunc (x:: FD{T, f} ) where {T, f} = FD {T, f} (div (x. i, coefficient (FD{T, f})))
196
- floor (x:: FD{T, f} ) where {T, f} = FD {T, f} (fld (x. i, coefficient (FD{T, f})))
189
+ Base . trunc (x:: FD{T, f} ) where {T, f} = FD {T, f} (div (x. i, coefficient (FD{T, f})))
190
+ Base . floor (x:: FD{T, f} ) where {T, f} = FD {T, f} (fld (x. i, coefficient (FD{T, f})))
197
191
198
192
# TODO : round with number of digits; should be easy
199
- function round (x:: FD{T, f} , :: RoundingMode{:Nearest} = RoundNearest) where {T, f}
193
+ function Base . round (x:: FD{T, f} , :: RoundingMode{:Nearest} = RoundNearest) where {T, f}
200
194
powt = coefficient (FD{T, f})
201
195
quotient, remainder = fldmodinline (x. i, powt)
202
196
FD {T, f} (_round_to_even (quotient, remainder, powt))
203
197
end
204
- function ceil (x:: FD{T, f} ) where {T, f}
198
+ function Base . ceil (x:: FD{T, f} ) where {T, f}
205
199
powt = coefficient (FD{T, f})
206
200
quotient, remainder = fldmodinline (x. i, powt)
207
201
if remainder > 0
@@ -243,44 +237,44 @@ end
243
237
_apply_exact_float (f, :: Type{T} , x:: Real , i:: Integer ) where T = f (T, x, i)
244
238
245
239
for fn in [:trunc , :floor , :ceil ]
246
- @eval ($ fn (:: Type{TI} , x:: FD ):: TI ) where {TI <: Integer } = $ fn (x)
240
+ @eval (Base. $ fn (:: Type{TI} , x:: FD ):: TI ) where {TI <: Integer } = $ fn (x)
247
241
248
242
# round/trunc/ceil/flooring to FD; generic
249
- @eval function $fn (:: Type{FD{T, f}} , x:: Real ) where {T, f}
243
+ @eval function Base . $fn (:: Type{FD{T, f}} , x:: Real ) where {T, f}
250
244
powt = coefficient (FD{T, f})
251
245
# Use machine Float64 if possible, but fall back to BigFloat if we need
252
246
# more precision. 4f bits suffices.
253
247
val = _apply_exact_float ($ (Symbol (fn, " mul" )), T, x, powt)
254
248
reinterpret (FD{T, f}, val)
255
249
end
256
250
end
257
- function round (:: Type{TI} , x:: FD , :: RoundingMode{:Nearest} = RoundNearest) where {TI <: Integer }
251
+ function Base . round (:: Type{TI} , x:: FD , :: RoundingMode{:Nearest} = RoundNearest) where {TI <: Integer }
258
252
convert (TI, round (x)):: TI
259
253
end
260
- function round (:: Type{FD{T, f}} , x:: Real , :: RoundingMode{:Nearest} = RoundNearest) where {T, f}
254
+ function Base . round (:: Type{FD{T, f}} , x:: Real , :: RoundingMode{:Nearest} = RoundNearest) where {T, f}
261
255
reinterpret (FD{T, f}, round (T, x * coefficient (FD{T, f})))
262
256
end
263
257
264
258
# needed to avoid ambiguity
265
- function round (:: Type{FD{T, f}} , x:: Rational , :: RoundingMode{:Nearest} = RoundNearest) where {T, f}
259
+ function Base . round (:: Type{FD{T, f}} , x:: Rational , :: RoundingMode{:Nearest} = RoundNearest) where {T, f}
266
260
reinterpret (FD{T, f}, round (T, x * coefficient (FD{T, f})))
267
261
end
268
262
269
263
# conversions and promotions
270
- convert (:: Type{FD{T, f}} , x:: FD{T, f} ) where {T, f} = x # Converting an FD to itself is a no-op
264
+ Base . convert (:: Type{FD{T, f}} , x:: FD{T, f} ) where {T, f} = x # Converting an FD to itself is a no-op
271
265
272
- function convert (:: Type{FD{T, f}} , x:: Integer ) where {T, f}
266
+ function Base . convert (:: Type{FD{T, f}} , x:: Integer ) where {T, f}
273
267
reinterpret (FD{T, f}, T (widemul (x, coefficient (FD{T, f}))))
274
268
end
275
269
276
- convert (:: Type{T} , x:: AbstractFloat ) where {T <: FD } = round (T, x)
270
+ Base . convert (:: Type{T} , x:: AbstractFloat ) where {T <: FD } = round (T, x)
277
271
278
- function convert (:: Type{FD{T, f}} , x:: Rational ) where {T, f}
272
+ function Base . convert (:: Type{FD{T, f}} , x:: Rational ) where {T, f}
279
273
powt = coefficient (FD{T, f})
280
274
reinterpret (FD{T, f}, T (x * powt)):: FD{T, f}
281
275
end
282
276
283
- function convert (:: Type{FD{T, f}} , x:: FD{U, g} ) where {T, f, U, g}
277
+ function Base . convert (:: Type{FD{T, f}} , x:: FD{U, g} ) where {T, f, U, g}
284
278
if f ≥ g
285
279
# Compute `10^(f - g)` without overflow
286
280
powt = div (coefficient (FD{T, f}), coefficient (FD{U, g}))
@@ -298,7 +292,7 @@ function convert(::Type{FD{T, f}}, x::FD{U, g}) where {T, f, U, g}
298
292
end
299
293
300
294
for remfn in [:rem , :mod , :mod1 , :min , :max ]
301
- @eval $ remfn (x:: T , y:: T ) where {T <: FD } = reinterpret (T, $ remfn (x. i, y. i))
295
+ @eval Base. $ remfn (x:: T , y:: T ) where {T <: FD } = reinterpret (T, $ remfn (x. i, y. i))
302
296
end
303
297
# TODO : When we upgrade to a min julia version >=1.4 (i.e Julia 2.0), this block can be
304
298
# dropped in favor of three-argument `div`, below.
@@ -313,33 +307,33 @@ if VERSION >= v"1.4.0-"
313
307
Base. div (x:: T , y:: T , r:: RoundingMode ) where {T <: FD } = T (div (x. i, y. i, r))
314
308
end
315
309
316
- convert (:: Type{AbstractFloat} , x:: FD ) = convert (floattype (typeof (x)), x)
317
- function convert (:: Type{TF} , x:: FD{T, f} ) where {TF <: AbstractFloat , T, f}
310
+ Base . convert (:: Type{AbstractFloat} , x:: FD ) = convert (floattype (typeof (x)), x)
311
+ function Base . convert (:: Type{TF} , x:: FD{T, f} ) where {TF <: AbstractFloat , T, f}
318
312
convert (TF, x. i / coefficient (FD{T, f})):: TF
319
313
end
320
314
321
- function convert (:: Type{TF} , x:: FD{T, f} ) where {TF <: BigFloat , T, f}
315
+ function Base . convert (:: Type{TF} , x:: FD{T, f} ) where {TF <: BigFloat , T, f}
322
316
convert (TF, BigInt (x. i) / BigInt (coefficient (FD{T, f}))):: TF
323
317
end
324
318
325
- function convert (:: Type{TI} , x:: FD{T, f} ) where {TI <: Integer , T, f}
319
+ function Base . convert (:: Type{TI} , x:: FD{T, f} ) where {TI <: Integer , T, f}
326
320
isinteger (x) || throw (InexactError (:convert , TI, x))
327
321
convert (TI, div (x. i, coefficient (FD{T, f}))):: TI
328
322
end
329
323
330
- function convert (:: Type{TR} , x:: FD{T, f} ) where {TR <: Rational , T, f}
324
+ function Base . convert (:: Type{TR} , x:: FD{T, f} ) where {TR <: Rational , T, f}
331
325
convert (TR, x. i // coefficient (FD{T, f})):: TR
332
326
end
333
327
334
328
(:: Type{T} )(x:: FD ) where {T<: Union{AbstractFloat,Integer,Rational} } = convert (T, x)
335
329
336
- promote_rule (:: Type{FD{T, f}} , :: Type{<:Integer} ) where {T, f} = FD{T, f}
337
- promote_rule (:: Type{<:FD} , :: Type{TF} ) where {TF <: AbstractFloat } = TF
338
- promote_rule (:: Type{<:FD} , :: Type{Rational{TR}} ) where {TR} = Rational{TR}
330
+ Base . promote_rule (:: Type{FD{T, f}} , :: Type{<:Integer} ) where {T, f} = FD{T, f}
331
+ Base . promote_rule (:: Type{<:FD} , :: Type{TF} ) where {TF <: AbstractFloat } = TF
332
+ Base . promote_rule (:: Type{<:FD} , :: Type{Rational{TR}} ) where {TR} = Rational{TR}
339
333
340
334
# TODO : decide if these are the right semantics;
341
335
# right now we pick the bigger int type and the bigger decimal point
342
- Base . @pure function promote_rule (:: Type{FD{T, f}} , :: Type{FD{U, g}} ) where {T, f, U, g}
336
+ @pure function Base . promote_rule (:: Type{FD{T, f}} , :: Type{FD{U, g}} ) where {T, f, U, g}
343
337
FD{promote_type (T, U), max (f, g)}
344
338
end
345
339
@@ -348,24 +342,24 @@ Base.zero(::Type{FD{T, f}}) where {T, f} = reinterpret(FD{T, f}, zero(T))
348
342
Base. one (:: Type{FD{T, f}} ) where {T, f} = reinterpret (FD{T, f}, coefficient (FD{T, f}))
349
343
350
344
# comparison
351
- == (x:: T , y:: T ) where {T <: FD } = x. i == y. i
352
- < (x:: T , y:: T ) where {T <: FD } = x. i < y. i
353
- <= (x:: T , y:: T ) where {T <: FD } = x. i <= y. i
345
+ Base.:( == ) (x:: T , y:: T ) where {T <: FD } = x. i == y. i
346
+ Base.:( < ) (x:: T , y:: T ) where {T <: FD } = x. i < y. i
347
+ Base.:( <= ) (x:: T , y:: T ) where {T <: FD } = x. i <= y. i
354
348
355
349
# predicates and traits
356
- isinteger (x:: FD{T, f} ) where {T, f} = rem (x. i, coefficient (FD{T, f})) == 0
357
- typemin (:: Type{FD{T, f}} ) where {T, f} = reinterpret (FD{T, f}, typemin (T))
358
- typemax (:: Type{FD{T, f}} ) where {T, f}= reinterpret (FD{T, f}, typemax (T))
359
- eps (:: Type{T} ) where {T <: FD } = reinterpret (T, 1 )
360
- eps (x:: FD ) = eps (typeof (x))
361
- floatmin (:: Type{T} ) where {T <: FD } = eps (T)
362
- floatmax (:: Type{T} ) where {T <: FD } = typemax (T)
350
+ Base . isinteger (x:: FD{T, f} ) where {T, f} = rem (x. i, coefficient (FD{T, f})) == 0
351
+ Base . typemin (:: Type{FD{T, f}} ) where {T, f} = reinterpret (FD{T, f}, typemin (T))
352
+ Base . typemax (:: Type{FD{T, f}} ) where {T, f}= reinterpret (FD{T, f}, typemax (T))
353
+ Base . eps (:: Type{T} ) where {T <: FD } = reinterpret (T, 1 )
354
+ Base . eps (x:: FD ) = eps (typeof (x))
355
+ Base . floatmin (:: Type{T} ) where {T <: FD } = eps (T)
356
+ Base . floatmax (:: Type{T} ) where {T <: FD } = typemax (T)
363
357
364
358
# printing
365
- function print (io:: IO , x:: FD{T, 0} ) where T
359
+ function Base . print (io:: IO , x:: FD{T, 0} ) where T
366
360
print (io, x. i)
367
361
end
368
- function print (io:: IO , x:: FD{T, f} ) where {T, f}
362
+ function Base . print (io:: IO , x:: FD{T, f} ) where {T, f}
369
363
iscompact = get (io, :compact , false )
370
364
371
365
# note: a is negative if x.i == typemin(x.i)
@@ -387,7 +381,7 @@ function print(io::IO, x::FD{T, f}) where {T, f}
387
381
print (io, integer, ' .' , fractionchars)
388
382
end
389
383
390
- function show (io:: IO , x:: FD{T, f} ) where {T, f}
384
+ function Base . show (io:: IO , x:: FD{T, f} ) where {T, f}
391
385
iscompact = get (io, :compact , false )
392
386
if ! iscompact
393
387
print (io, " FixedDecimal{$T ,$f }(" )
@@ -407,7 +401,7 @@ Raises an `InexactError` if any rounding is necessary.
407
401
"""
408
402
const RoundThrows = RoundingMode {:Throw} ()
409
403
410
- function parse (:: Type{FD{T, f}} , str:: AbstractString , mode:: RoundingMode = RoundNearest) where {T, f}
404
+ function Base . parse (:: Type{FD{T, f}} , str:: AbstractString , mode:: RoundingMode = RoundNearest) where {T, f}
411
405
if ! (mode in [RoundThrows, RoundNearest, RoundToZero])
412
406
throw (ArgumentError (" Unhandled rounding mode $mode " ))
413
407
end
@@ -475,12 +469,17 @@ end
475
469
476
470
The highest value of `x` which does not result in an overflow when evaluating `T(10)^x`. For
477
471
types of `T` that do not overflow -1 will be returned.
478
- """
479
- Base. @pure function max_exp10 (:: Type{T} ) where {T <: Integer }
480
- # This function is marked as `Base.@pure`. Even though it does call some generic
481
- # functions, they are all simple methods that should be able to be evaluated as
482
- # constants. This function does not have or depend on any side-effects.
483
472
473
+ NOTE: This function is expensive, since it contains a while-loop, but it is actually
474
+ computing a constant value for types, so it really only needs to be run once per type.
475
+ We achieve this by `@eval`ing new methods in a loop, below. Users can do this
476
+ themselves to add more "frozen" methods for custom Integer types:
477
+ ```julia
478
+ @eval FixedPointDecimals.max_exp10(::Type{CustomIntType}) = \$ (max_exp10(CustomIntType))
479
+ ```
480
+ This function does not have or depend on any side-effects.
481
+ """
482
+ function max_exp10 (:: Type{T} ) where {T <: Integer }
484
483
W = widen (T)
485
484
type_max = W (typemax (T))
486
485
@@ -497,9 +496,13 @@ Base.@pure function max_exp10(::Type{T}) where {T <: Integer}
497
496
end
498
497
499
498
max_exp10 (:: Type{BigInt} ) = - 1
500
- # Freeze the evaluation for Int128, since max_exp10(Int128) is too compilicated to get
501
- # optimized away by the compiler during const-folding.
502
- @eval max_exp10 (:: Type{Int128} ) = $ (max_exp10 (Int128))
499
+
500
+ # Freeze the evaluation for BitInteger types, since max_exp10() is too compilicated to get
501
+ # optimized away by the compiler during const-folding. (We can't freeze for user-defined
502
+ # types because we don't know what they are yet.)
503
+ for T in Base. BitInteger_types
504
+ @eval max_exp10 (:: Type{$T} ) = $ (max_exp10 (T))
505
+ end
503
506
504
507
# coefficient is marked pure. This is needed to ensure that the result is always available
505
508
# at compile time, and can therefore be used when optimizing mathematical operations.
@@ -509,11 +512,11 @@ max_exp10(::Type{BigInt}) = -1
509
512
Compute `10^f` as an Integer without overflow. Note that overflow will not occur for any
510
513
constructable `FD{T, f}`.
511
514
"""
512
- Base . @pure coefficient (:: Type{FD{T, f}} ) where {T, f} = T (10 )^ f
513
- Base . @pure coefficient (fd:: FD{T, f} ) where {T, f} = coefficient (FD{T, f})
515
+ @pure coefficient (:: Type{FD{T, f}} ) where {T, f} = T (10 )^ f
516
+ @pure coefficient (fd:: FD{T, f} ) where {T, f} = coefficient (FD{T, f})
514
517
value (fd:: FD ) = fd. i
515
518
516
519
# for generic hashing
517
- decompose (fd:: FD ) = decompose (Rational (fd))
520
+ Base . decompose (fd:: FD ) = decompose (Rational (fd))
518
521
519
522
end
0 commit comments