Skip to content

Commit dfddeec

Browse files
jmkuhnstevengj
authored andcommitted
Round without overflow (Fix #59) (#64)
1 parent b9fcccc commit dfddeec

File tree

2 files changed

+21
-14
lines changed

2 files changed

+21
-14
lines changed

src/DecFP.jl

+19-12
Original file line numberDiff line numberDiff line change
@@ -150,15 +150,20 @@ for w in (32,64,128)
150150

151151
$BID(x::AbstractString) = parse($BID, x)
152152

153+
function tostring(x::$BID)
154+
# fills global _buffer
155+
ccall(($(bidsym(w,"to_string")), libbid), Cvoid, (Ptr{UInt8}, $BID), _buffer, x)
156+
end
157+
153158
function Base.show(io::IO, x::$BID)
154159
isnan(x) && (write(io, "NaN"); return)
155160
isinf(x) && (write(io, signbit(x) ? "-Inf" : "Inf"); return)
156161
x == 0 && (write(io, signbit(x) ? "-0.0" : "0.0"); return)
157-
ccall(($(bidsym(w,"to_string")), libbid), Cvoid, (Ptr{UInt8}, $BID), _buffer, x)
162+
tostring(x)
158163
if _buffer[1] == UInt8('-')
159164
write(io, '-')
160165
end
161-
normalized_exponent = nox(ccall(($(bidsym(w,"ilogb")), libbid), Cint, ($BID,), x))
166+
normalized_exponent = exponent10(x)
162167
lastdigitindex = Compat.findfirst(equalto(UInt8('E')), _buffer) - 1
163168
lastnonzeroindex = Compat.findlast(!equalto(UInt8('0')), view(_buffer, 1:lastdigitindex))
164169
if -5 < normalized_exponent < 6
@@ -210,13 +215,12 @@ for w in (32,64,128)
210215
if n > length(DIGITS) - 1
211216
n = length(DIGITS) - 1
212217
end
213-
# rounded = round(x * exp10($BID(n)), RoundNearestTiesAway)
214-
rounded = @xchk(ccall(($(bidsym(w,"round_integral_nearest_away")), libbid), $BID, ($BID,), x * exp10($BID(n))), InexactError, :round, $BID, x, mask=INVALID | OVERFLOW)
218+
rounded = round(ldexp10(x, n), RoundNearestTiesAway)
215219
if rounded == 0
216220
DIGITS[1] = UInt8('0')
217221
return Int32(1), Int32(1), signbit(x)
218222
end
219-
ccall(($(bidsym(w,"to_string")), libbid), Cvoid, (Ptr{UInt8}, $BID), _buffer, rounded)
223+
tostring(rounded)
220224
trailing_zeros = 0
221225
i = 2
222226
while _buffer[i] != UInt8('E')
@@ -258,16 +262,19 @@ for w in (32,64,128)
258262
end
259263
return Int32(1), Int32(1), signbit(x)
260264
end
261-
normalized_exponent = nox(ccall(($(bidsym(w,"ilogb")), libbid), Cint, ($BID,), x))
262-
# rounded = round(x * exp10($BID(n - 1 - normalized_exponent)), RoundNearestTiesAway)
263-
rounded = @xchk(ccall(($(bidsym(w,"round_integral_nearest_away")), libbid), $BID, ($BID,), x * exp10($BID(n - 1 - normalized_exponent))), InexactError, :round, $BID, x, mask=INVALID | OVERFLOW)
264-
rounded_exponent = nox(ccall(($(bidsym(w,"ilogb")), libbid), Cint, ($BID,), rounded))
265-
ccall(($(bidsym(w,"to_string")), libbid), Cvoid, (Ptr{UInt8}, $BID), _buffer, rounded)
265+
normalized_exponent = exponent10(x)
266+
rounded = round(ldexp10(x, n - 1 - normalized_exponent), RoundNearestTiesAway)
267+
rounded_exponent = exponent10(rounded)
268+
tostring(rounded)
266269
i = 2
267270
while _buffer[i] != UInt8('E')
268271
DIGITS[i - 1] = _buffer[i]
269272
i += 1
270273
end
274+
while i <= n + 1
275+
DIGITS[i - 1] = UInt8('0')
276+
i += 1
277+
end
271278
pt = normalized_exponent + rounded_exponent - n + 2
272279
neg = signbit(x)
273280
return Int32(n), Int32(pt), neg
@@ -287,8 +294,8 @@ for w in (32,64,128)
287294
Base.eps(x::$BID) = ifelse(isfinite(x), @xchk(nextfloat(x) - x, OverflowError, "$($BID) value overflow", mask=OVERFLOW), $(_parse(T, "NaN")))
288295

289296
# the meaning of the exponent is different than for binary FP: it is 10^n, not 2^n:
290-
# Base.exponent(x::$BID) = nox(ccall(($(bidsym(w,"ilogb")), libbid), Cint, ($BID,), x))
291-
# Base.ldexp(x::$BID, n::Integer) = nox(ccall(($(bidsym(w,"ldexp")), libbid), $BID, ($BID,Cint), x, n))
297+
exponent10(x::$BID) = nox(ccall(($(bidsym(w,"ilogb")), libbid), Cint, ($BID,), x))
298+
ldexp10(x::$BID, n::Integer) = nox(ccall(($(bidsym(w,"ldexp")), libbid), $BID, ($BID,Cint), x, n))
292299
end
293300

294301
for (f,c) in ((:isnan,"isNaN"), (:isinf,"isInf"), (:isfinite,"isFinite"), (:issubnormal,"isSubnormal"))

test/runtests.jl

+2-2
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,8 @@ for T in (Dec32, Dec64, Dec128)
195195
@test_throws DomainError sqrt(yd)
196196
@test_throws DomainError acosh(zd)
197197

198-
# @test ldexp(parse(T, "1"), 3) == 1000
199-
# @test exponent(parse(T, "1000")) == 3
198+
@test DecFP.ldexp10(parse(T, "1"), 3) == 1000
199+
@test DecFP.exponent10(parse(T, "1000")) == 3
200200
@test sqrt(complex(yd)) sqrt(complex(y))
201201

202202
@test typeof(xd * pi) == T

0 commit comments

Comments
 (0)