@@ -30,7 +30,7 @@ using Compat
30
30
import Base: reinterpret, zero, one, abs, sign, == , < , <= , + , - , / , * , div,
31
31
rem, divrem, fld, mod, fldmod, fld1, mod1, fldmod1, isinteger,
32
32
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
34
34
35
35
"""
36
36
FixedDecimal{I <: Integer, f::Int}
@@ -59,6 +59,17 @@ abs{T, f}(x::FD{T, f}) = reinterpret(FD{T, f}, abs(x.i))
59
59
+ {T, f}(x:: FD{T, f} , y:: FD{T, f} ) = reinterpret (FD{T, f}, x. i+ y. i)
60
60
- {T, f}(x:: FD{T, f} , y:: FD{T, f} ) = reinterpret (FD{T, f}, x. i- y. i)
61
61
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
+
62
73
function _round_to_even (quotient, remainder, powt)
63
74
if powt == 1
64
75
quotient
99
110
trunc {T, f} (x:: FD{T, f} ) = FD {T, f} (div (x. i, T (10 )^ f))
100
111
floor {T, f} (x:: FD{T, f} ) = FD {T, f} (fld (x. i, T (10 )^ f))
101
112
# 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 )
103
114
powt = T (10 )^ f
104
115
quotient, remainder = fldmod (x. i, powt)
105
116
FD {T, f} (_round_to_even (quotient, remainder, powt))
@@ -114,17 +125,35 @@ function ceil{T, f}(x::FD{T, f})
114
125
end
115
126
end
116
127
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))
119
149
end
120
150
121
151
# conversions and promotions
122
152
convert {T, f} (:: Type{FD{T, f}} , x:: Integer ) =
123
153
reinterpret (FD{T, f}, round (T, Base. widemul (T (x), T (10 )^ f)))
124
154
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
+
128
157
function convert {T, f} (:: Type{FD{T, f}} , x:: Rational ):: FD{T, f}
129
158
powt = T (10 )^ f
130
159
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}
171
200
promote_rule {T, f, TF <: AbstractFloat} (:: Type{FD{T, f}} , :: Type{TF} ) = TF
172
201
promote_rule {T, f, TR} (:: Type{FD{T, f}} , :: Type{Rational{TR}} ) = Rational{TR}
173
202
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
+
174
208
# comparison
175
209
== {T <: FD }(x:: T , y:: T ) = x. i == y. i
176
210
< {T <: FD }(x:: T , y:: T ) = x. i < y. i
0 commit comments