Skip to content

Commit 815452a

Browse files
NHDalyomus
authored andcommitted
Optimize zero(FD{T,f}): implement via reinterpret not convert. (#46)
* Optimize zero(FD{T,f}): reinterpret not convert. I also noticed, though, that reinterpret() is still not fully const-folding. It often folds away in simple constructions, but inside complex expressions it isn't. I fixed this by marking both `reinterpret` and `max_exp10` as `Base.@pure`. * Add comment explaining motivation for `Base.zero(FD)` * Spacing fix in src/FixedPointDecimals.jl Co-Authored-By: NHDaly <NHDaly@gmail.com> * Also optimize `Base.one` to fully const-fold. - Add definition for Base.one(::Type{FD{T,f}}) - Mark coefficient(::Type{FD{T,f}}) as `Base.@pure` as well. * Update comment for coefficient being `@pure`
1 parent 315e5cb commit 815452a

File tree

1 file changed

+15
-4
lines changed

1 file changed

+15
-4
lines changed

src/FixedPointDecimals.jl

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,8 @@ struct FixedDecimal{T <: Integer, f} <: Real
8585
i::T
8686

8787
# inner constructor
88-
function Base.reinterpret(::Type{FixedDecimal{T, f}}, i::Integer) where {T, f}
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}
8990
n = max_exp10(T)
9091
if f >= 0 && (n < 0 || f <= n)
9192
new{T, f}(i % T)
@@ -335,6 +336,10 @@ Base.@pure function promote_rule(::Type{FD{T, f}}, ::Type{FD{U, g}}) where {T, f
335336
FD{promote_type(T, U), max(f, g)}
336337
end
337338

339+
# The default `zero` and `one` call `convert`, which is expensive, so we call reinterpret.
340+
Base.zero(::Type{FD{T, f}}) where {T, f} = reinterpret(FD{T, f}, zero(T))
341+
Base.one(::Type{FD{T, f}}) where {T, f} = reinterpret(FD{T, f}, coefficient(FD{T, f}))
342+
338343
# comparison
339344
==(x::T, y::T) where {T <: FD} = x.i == y.i
340345
<(x::T, y::T) where {T <: FD} = x.i < y.i
@@ -464,7 +469,11 @@ end
464469
The highest value of `x` which does not result in an overflow when evaluating `T(10)^x`. For
465470
types of `T` that do not overflow -1 will be returned.
466471
"""
467-
function max_exp10(::Type{T}) where {T <: Integer}
472+
Base.@pure function max_exp10(::Type{T}) where {T <: Integer}
473+
# This function is marked as `Base.@pure`. Even though it does call some generic
474+
# functions, they are all simple methods that should be able to be evaluated as
475+
# constants. This function does not have or depend on any side-effects.
476+
468477
W = widen(T)
469478
type_max = W(typemax(T))
470479

@@ -485,14 +494,16 @@ max_exp10(::Type{BigInt}) = -1
485494
# optimized away by the compiler during const-folding.
486495
@eval max_exp10(::Type{Int128}) = $(max_exp10(Int128))
487496

497+
# coefficient is marked pure. This is needed to ensure that the result is always available
498+
# at compile time, and can therefore be used when optimizing mathematical operations.
488499
"""
489500
coefficient(::Type{FD{T, f}}) -> T
490501
491502
Compute `10^f` as an Integer without overflow. Note that overflow will not occur for any
492503
constructable `FD{T, f}`.
493504
"""
494-
coefficient(::Type{FD{T, f}}) where {T, f} = T(10)^f
495-
coefficient(fd::FD{T, f}) where {T, f} = coefficient(FD{T, f})
505+
Base.@pure coefficient(::Type{FD{T, f}}) where {T, f} = T(10)^f
506+
Base.@pure coefficient(fd::FD{T, f}) where {T, f} = coefficient(FD{T, f})
496507
value(fd::FD) = fd.i
497508

498509
# for generic hashing

0 commit comments

Comments
 (0)