Skip to content

Commit 5008aba

Browse files
TotalVerbomus
authored andcommitted
Improve testing of FixedPointDecimal (#72)
1 parent 31251fd commit 5008aba

File tree

3 files changed

+228
-88
lines changed

3 files changed

+228
-88
lines changed

REQUIRE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
julia 0.5
2+
Compat 0.17.0

src/FixedPointDecimals.jl

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ using Compat
3030
import Base: reinterpret, zero, one, abs, sign, ==, <, <=, +, -, /, *, div,
3131
rem, divrem, fld, mod, fldmod, fld1, mod1, fldmod1, isinteger,
3232
typemin, typemax, realmin, realmax, show, convert, promote_rule,
33-
min, max, trunc, round, floor, ceil, eps, float
33+
min, max, trunc, round, floor, ceil, eps, float, widemul
3434

3535
"""
3636
FixedDecimal{I <: Integer, f::Int}
@@ -59,6 +59,17 @@ abs{T, f}(x::FD{T, f}) = reinterpret(FD{T, f}, abs(x.i))
5959
+{T, f}(x::FD{T, f}, y::FD{T, f}) = reinterpret(FD{T, f}, x.i+y.i)
6060
-{T, f}(x::FD{T, f}, y::FD{T, f}) = reinterpret(FD{T, f}, x.i-y.i)
6161

62+
# wide multiplication
63+
Base.@pure function widemul{T, f, U, g}(x::FD{T, f}, y::FD{U, g})
64+
i = widemul(x.i, y.i)
65+
reinterpret(FD{typeof(i), f + g}, i)
66+
end
67+
Base.@pure function widemul{T, f}(x::FD{T, f}, y::Integer)
68+
i = widemul(x.i, y)
69+
reinterpret(FD{typeof(i), f}, i)
70+
end
71+
Base.@pure widemul(x::Integer, y::FD) = widemul(y, x)
72+
6273
function _round_to_even(quotient, remainder, powt)
6374
if powt == 1
6475
quotient
@@ -99,7 +110,7 @@ end
99110
trunc{T, f}(x::FD{T, f}) = FD{T, f}(div(x.i, T(10)^f))
100111
floor{T, f}(x::FD{T, f}) = FD{T, f}(fld(x.i, T(10)^f))
101112
# TODO: round with number of digits; should be easy
102-
function round{T, f}(x::FD{T, f})
113+
function round{T, f}(x::FD{T, f}, ::RoundingMode{:Nearest}=RoundNearest)
103114
powt = T(10)^f
104115
quotient, remainder = fldmod(x.i, powt)
105116
FD{T, f}(_round_to_even(quotient, remainder, powt))
@@ -114,17 +125,35 @@ function ceil{T, f}(x::FD{T, f})
114125
end
115126
end
116127

117-
for truncfn in [:trunc, :round, :floor, :ceil]
118-
@eval $truncfn{TI}(::Type{TI}, x::FD)::TI = $truncfn(x)
128+
for truncfn in [:trunc, :floor, :ceil]
129+
@eval $truncfn{TI <: Integer}(::Type{TI}, x::FD)::TI = $truncfn(x)
130+
131+
# round/trunc/ceil/flooring to FD; generic
132+
# TODO. this is probably incorrect for floating point and we need to check
133+
# overflow in other cases.
134+
@eval function $truncfn{T, f}(::Type{FD{T, f}}, x::Real)
135+
reinterpret(FD{T, f}, $truncfn(T, T(10)^f * x))
136+
end
137+
end
138+
round{TI <: Integer}(::Type{TI}, x::FD,
139+
::RoundingMode{:Nearest}=RoundNearest)::TI = round(x)
140+
function round{T, f}(::Type{FD{T, f}}, x::Real,
141+
::RoundingMode{:Nearest}=RoundNearest)
142+
reinterpret(FD{T, f}, round(T, T(10)^f * x))
143+
end
144+
145+
# needed to avoid ambiguity
146+
function round{T, f}(::Type{FD{T, f}}, x::Rational,
147+
::RoundingMode{:Nearest}=RoundNearest)
148+
reinterpret(FD{T, f}, round(T, T(10)^f * x))
119149
end
120150

121151
# conversions and promotions
122152
convert{T, f}(::Type{FD{T, f}}, x::Integer) =
123153
reinterpret(FD{T, f}, round(T, Base.widemul(T(x), T(10)^f)))
124154

125-
# TODO. this is very, very incorrect.
126-
convert{T, f}(::Type{FD{T, f}}, x::AbstractFloat) =
127-
reinterpret(FD{T, f}, round(T, T(10)^f * x))
155+
convert{T <: FD}(::Type{T}, x::AbstractFloat) = round(T, x)
156+
128157
function convert{T, f}(::Type{FD{T, f}}, x::Rational)::FD{T, f}
129158
powt = T(10)^f
130159
num::T, den::T = numerator(x), denominator(x)
@@ -171,6 +200,11 @@ promote_rule{T, f, TI <: Integer}(::Type{FD{T, f}}, ::Type{TI}) = FD{T, f}
171200
promote_rule{T, f, TF <: AbstractFloat}(::Type{FD{T, f}}, ::Type{TF}) = TF
172201
promote_rule{T, f, TR}(::Type{FD{T, f}}, ::Type{Rational{TR}}) = Rational{TR}
173202

203+
# TODO: decide if these are the right semantics;
204+
# right now we pick the bigger int type and the bigger decimal point
205+
Base.@pure promote_rule{T, f, U, g}(::Type{FD{T, f}}, ::Type{FD{U, g}}) =
206+
FD{promote_type(T, U), max(f, g)}
207+
174208
# comparison
175209
=={T <: FD}(x::T, y::T) = x.i == y.i
176210
<{T <: FD}(x::T, y::T) = x.i < y.i

0 commit comments

Comments
 (0)