@@ -27,13 +27,7 @@ module FixedPointDecimals
2727
2828export FixedDecimal, RoundThrows
2929
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
3731
3832# floats that support fma and are roughly IEEE-like
3933const FMAFloat = Union{Float16, Float32, Float64, BigFloat}
@@ -85,8 +79,8 @@ struct FixedDecimal{T <: Integer, f} <: Real
8579 i:: T
8680
8781 # 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}
9084 n = max_exp10 (T)
9185 if f >= 0 && (n < 0 || f <= n)
9286 new {T, f} (i % T)
@@ -114,22 +108,22 @@ floattype(::Type{<:FD{T}}) where {T<:Integer} = Float64
114108floattype (:: Type{<:FD{BigInt}} ) = BigFloat
115109
116110# 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))
119113
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)
122116
123117# 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}
125119 i = widemul (x. i, y. i)
126120 reinterpret (FD{typeof (i), f + g}, i)
127121end
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}
129123 i = widemul (x. i, y)
130124 reinterpret (FD{typeof (i), f}, i)
131125end
132- Base . @pure widemul (x:: Integer , y:: FD ) = widemul (y, x)
126+ @pure Base . widemul (x:: Integer , y:: FD ) = widemul (y, x)
133127
134128"""
135129 _round_to_even(quotient, remainder, divisor)
@@ -160,48 +154,48 @@ _round_to_even(q, r, d) = _round_to_even(promote(q, r, d)...)
160154# multiplication rounds to nearest even representation
161155# TODO : can we use floating point to speed this up? after we build a
162156# 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}
164158 powt = coefficient (FD{T, f})
165159 quotient, remainder = fldmodinline (widemul (x. i, y. i), powt)
166160 reinterpret (FD{T, f}, _round_to_even (quotient, remainder, powt))
167161end
168162
169163# these functions are needed to avoid InexactError when converting from the
170164# 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))
173167
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}
175169 powt = coefficient (FD{T, f})
176170 quotient, remainder = fldmod (widemul (x. i, powt), y. i)
177171 reinterpret (FD{T, f}, T (_round_to_even (quotient, remainder, y. i)))
178172end
179173
180174# These functions allow us to perform division with integers outside of the range of the
181175# FixedDecimal.
182- function / (x:: Integer , y:: FD{T, f} ) where {T, f}
176+ function Base.: / (x:: Integer , y:: FD{T, f} ) where {T, f}
183177 powt = coefficient (FD{T, f})
184178 powtsq = widemul (powt, powt)
185179 quotient, remainder = fldmod (widemul (x, powtsq), y. i)
186180 reinterpret (FD{T, f}, T (_round_to_even (quotient, remainder, y. i)))
187181end
188182
189- function / (x:: FD{T, f} , y:: Integer ) where {T, f}
183+ function Base.: / (x:: FD{T, f} , y:: Integer ) where {T, f}
190184 quotient, remainder = fldmod (x. i, y)
191185 reinterpret (FD{T, f}, T (_round_to_even (quotient, remainder, y)))
192186end
193187
194188# 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})))
197191
198192# 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}
200194 powt = coefficient (FD{T, f})
201195 quotient, remainder = fldmodinline (x. i, powt)
202196 FD {T, f} (_round_to_even (quotient, remainder, powt))
203197end
204- function ceil (x:: FD{T, f} ) where {T, f}
198+ function Base . ceil (x:: FD{T, f} ) where {T, f}
205199 powt = coefficient (FD{T, f})
206200 quotient, remainder = fldmodinline (x. i, powt)
207201 if remainder > 0
@@ -243,44 +237,44 @@ end
243237_apply_exact_float (f, :: Type{T} , x:: Real , i:: Integer ) where T = f (T, x, i)
244238
245239for 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)
247241
248242 # 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}
250244 powt = coefficient (FD{T, f})
251245 # Use machine Float64 if possible, but fall back to BigFloat if we need
252246 # more precision. 4f bits suffices.
253247 val = _apply_exact_float ($ (Symbol (fn, " mul" )), T, x, powt)
254248 reinterpret (FD{T, f}, val)
255249 end
256250end
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 }
258252 convert (TI, round (x)):: TI
259253end
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}
261255 reinterpret (FD{T, f}, round (T, x * coefficient (FD{T, f})))
262256end
263257
264258# 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}
266260 reinterpret (FD{T, f}, round (T, x * coefficient (FD{T, f})))
267261end
268262
269263# 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
271265
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}
273267 reinterpret (FD{T, f}, T (widemul (x, coefficient (FD{T, f}))))
274268end
275269
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)
277271
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}
279273 powt = coefficient (FD{T, f})
280274 reinterpret (FD{T, f}, T (x * powt)):: FD{T, f}
281275end
282276
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}
284278 if f ≥ g
285279 # Compute `10^(f - g)` without overflow
286280 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}
298292end
299293
300294for 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))
302296end
303297# TODO : When we upgrade to a min julia version >=1.4 (i.e Julia 2.0), this block can be
304298# dropped in favor of three-argument `div`, below.
@@ -313,33 +307,33 @@ if VERSION >= v"1.4.0-"
313307 Base. div (x:: T , y:: T , r:: RoundingMode ) where {T <: FD } = T (div (x. i, y. i, r))
314308end
315309
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}
318312 convert (TF, x. i / coefficient (FD{T, f})):: TF
319313end
320314
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}
322316 convert (TF, BigInt (x. i) / BigInt (coefficient (FD{T, f}))):: TF
323317end
324318
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}
326320 isinteger (x) || throw (InexactError (:convert , TI, x))
327321 convert (TI, div (x. i, coefficient (FD{T, f}))):: TI
328322end
329323
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}
331325 convert (TR, x. i // coefficient (FD{T, f})):: TR
332326end
333327
334328(:: Type{T} )(x:: FD ) where {T<: Union{AbstractFloat,Integer,Rational} } = convert (T, x)
335329
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}
339333
340334# TODO : decide if these are the right semantics;
341335# 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}
343337 FD{promote_type (T, U), max (f, g)}
344338end
345339
@@ -348,24 +342,24 @@ Base.zero(::Type{FD{T, f}}) where {T, f} = reinterpret(FD{T, f}, zero(T))
348342Base. one (:: Type{FD{T, f}} ) where {T, f} = reinterpret (FD{T, f}, coefficient (FD{T, f}))
349343
350344# 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
354348
355349# 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)
363357
364358# printing
365- function print (io:: IO , x:: FD{T, 0} ) where T
359+ function Base . print (io:: IO , x:: FD{T, 0} ) where T
366360 print (io, x. i)
367361end
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}
369363 iscompact = get (io, :compact , false )
370364
371365 # 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}
387381 print (io, integer, ' .' , fractionchars)
388382end
389383
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}
391385 iscompact = get (io, :compact , false )
392386 if ! iscompact
393387 print (io, " FixedDecimal{$T ,$f }(" )
@@ -407,7 +401,7 @@ Raises an `InexactError` if any rounding is necessary.
407401"""
408402const RoundThrows = RoundingMode {:Throw} ()
409403
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}
411405 if ! (mode in [RoundThrows, RoundNearest, RoundToZero])
412406 throw (ArgumentError (" Unhandled rounding mode $mode " ))
413407 end
@@ -475,12 +469,17 @@ end
475469
476470The highest value of `x` which does not result in an overflow when evaluating `T(10)^x`. For
477471types 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.
483472
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 }
484483 W = widen (T)
485484 type_max = W (typemax (T))
486485
@@ -497,9 +496,13 @@ Base.@pure function max_exp10(::Type{T}) where {T <: Integer}
497496end
498497
499498max_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
503506
504507# coefficient is marked pure. This is needed to ensure that the result is always available
505508# at compile time, and can therefore be used when optimizing mathematical operations.
@@ -509,11 +512,11 @@ max_exp10(::Type{BigInt}) = -1
509512Compute `10^f` as an Integer without overflow. Note that overflow will not occur for any
510513constructable `FD{T, f}`.
511514"""
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})
514517value (fd:: FD ) = fd. i
515518
516519# for generic hashing
517- decompose (fd:: FD ) = decompose (Rational (fd))
520+ Base . decompose (fd:: FD ) = decompose (Rational (fd))
518521
519522end
0 commit comments