@@ -34,8 +34,6 @@ import Base: reinterpret, zero, one, abs, sign, ==, <, <=, +, -, /, *, div,
34
34
typemin, typemax, realmin, realmax, print, show, string, convert, parse,
35
35
promote_rule, min, max, trunc, round, floor, ceil, eps, float, widemul
36
36
37
- import Base. Checked: checked_mul
38
-
39
37
const IEEEFloat = Union{Float16, Float32, Float64}
40
38
41
39
for fn in [:trunc , :floor , :ceil ]
@@ -109,18 +107,22 @@ Base.@pure function widemul{T, f}(x::FD{T, f}, y::Integer)
109
107
end
110
108
Base. @pure widemul (x:: Integer , y:: FD ) = widemul (y, x)
111
109
112
- function _round_to_even (quotient, remainder, powt)
113
- if powt == 1
114
- quotient
110
+ """
111
+ _round_to_even(quotient, remainder, divisor)
112
+
113
+ Round `quotient + remainder / divisor` to the nearest even integer, given that
114
+ `0 ≤ remainder < divisor` or `0 ≥ remainder > divisor`. (This assumption is
115
+ satisfied by the return value of `fldmod` in all cases, and the return value of
116
+ `divrem` in cases where `divisor` is known to be positive.)
117
+ """
118
+ function _round_to_even (quotient, remainder, divisor)
119
+ halfdivisor = divisor >> 1
120
+ if iseven (divisor) && remainder == halfdivisor
121
+ ifelse (iseven (quotient), quotient, quotient + one (quotient))
122
+ elseif abs (remainder) > abs (halfdivisor)
123
+ quotient + one (quotient)
115
124
else
116
- halfpowt = powt >> 1
117
- if remainder == halfpowt
118
- ifelse (iseven (quotient), quotient, quotient + one (quotient))
119
- elseif remainder < halfpowt
120
- quotient
121
- else
122
- quotient + one (quotient)
123
- end
125
+ quotient
124
126
end
125
127
end
126
128
@@ -138,26 +140,33 @@ end
138
140
* {T, f}(x:: Integer , y:: FD{T, f} ) = reinterpret (FD{T, f}, T (x * y. i))
139
141
* {T, f}(x:: FD{T, f} , y:: Integer ) = reinterpret (FD{T, f}, T (x. i * y))
140
142
141
- # TODO . this is probably wrong sometimes.
142
143
function / {T, f}(x:: FD{T, f} , y:: FD{T, f} )
143
144
powt = T (10 )^ f
144
- quotient, remainder = divrem ( x. i, y. i)
145
- reinterpret (FD{T, f}, quotient * powt + round (T , remainder / y. i * powt ))
145
+ quotient, remainder = fldmod ( widemul ( x. i, powt), widen ( y. i) )
146
+ reinterpret (FD{T, f}, T ( _round_to_even (quotient , remainder, widen ( y. i)) ))
146
147
end
147
148
148
149
# these functions are needed to avoid InexactError when converting from the integer type
149
150
function / {T, f}(x:: Integer , y:: FD{T, f} )
150
- powt = T (10 )^ f
151
- xi, yi = checked_mul (x, powt), y. i
152
- quotient, remainder = divrem (xi, yi)
153
- reinterpret (FD{T, f}, quotient * powt + round (T, remainder / yi * powt))
151
+ S = promote_type (typeof (x), T)
152
+ xi, yi = promote (x, y. i)
153
+
154
+ # The integer part of our result is x.i * 10^2f / y.i, so we need to
155
+ # double-widen to get a precise result.
156
+ powt = S (10 )^ f
157
+ powtsq = widemul (powt, powt)
158
+ quotient, remainder = fldmod (widemul (widen (xi), powtsq), widen (widen (yi)))
159
+
160
+ reinterpret (FD{T, f},
161
+ T (_round_to_even (quotient, remainder, widen (widen (yi)))))
154
162
end
155
163
156
164
function / {T, f}(x:: FD{T, f} , y:: Integer )
157
- powt = T (10 )^ f
158
- xi, yi = x. i, checked_mul (y, powt)
159
- quotient, remainder = divrem (xi, yi)
160
- reinterpret (FD{T, f}, quotient * powt + round (T, remainder / yi * powt))
165
+ S = promote_type (T, typeof (y))
166
+ xi, yi = promote (x. i, y)
167
+
168
+ quotient, remainder = fldmod (xi, yi)
169
+ reinterpret (FD{T, f}, T (_round_to_even (quotient, remainder, yi)))
161
170
end
162
171
163
172
# integerification
0 commit comments