@@ -34,8 +34,6 @@ import Base: reinterpret, zero, one, abs, sign, ==, <, <=, +, -, /, *, div,
3434 typemin, typemax, realmin, realmax, print, show, string, convert, parse,
3535 promote_rule, min, max, trunc, round, floor, ceil, eps, float, widemul
3636
37- import Base. Checked: checked_mul
38-
3937const IEEEFloat = Union{Float16, Float32, Float64}
4038
4139for fn in [:trunc , :floor , :ceil ]
@@ -109,18 +107,22 @@ Base.@pure function widemul{T, f}(x::FD{T, f}, y::Integer)
109107end
110108Base. @pure widemul (x:: Integer , y:: FD ) = widemul (y, x)
111109
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)
115124 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
124126 end
125127end
126128
@@ -138,26 +140,33 @@ end
138140* {T, f}(x:: Integer , y:: FD{T, f} ) = reinterpret (FD{T, f}, T (x * y. i))
139141* {T, f}(x:: FD{T, f} , y:: Integer ) = reinterpret (FD{T, f}, T (x. i * y))
140142
141- # TODO . this is probably wrong sometimes.
142143function / {T, f}(x:: FD{T, f} , y:: FD{T, f} )
143144 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)) ))
146147end
147148
148149# these functions are needed to avoid InexactError when converting from the integer type
149150function / {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)))))
154162end
155163
156164function / {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)))
161170end
162171
163172# integerification
0 commit comments