@@ -30,7 +30,7 @@ using Compat
3030import 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+
6273function _round_to_even (quotient, remainder, powt)
6374 if powt == 1
6475 quotient
99110trunc {T, f} (x:: FD{T, f} ) = FD {T, f} (div (x. i, T (10 )^ f))
100111floor {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
115126end
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))
119149end
120150
121151# conversions and promotions
122152convert {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+
128157function 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}
171200promote_rule {T, f, TF <: AbstractFloat} (:: Type{FD{T, f}} , :: Type{TF} ) = TF
172201promote_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