Skip to content

Commit 50d5aa8

Browse files
committed
WIP: use bit twiddling instead of ldexp for IEEE floats
1 parent c517246 commit 50d5aa8

File tree

2 files changed

+69
-10
lines changed

2 files changed

+69
-10
lines changed

base/float.jl

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,67 @@ signed integer, so that `abs(typemin(x)) == typemin(x) < 0`, in which case the r
148148
uabs(x::Integer) = abs(x)
149149
uabs(x::BitSigned) = unsigned(abs(x))
150150

151+
function float_representation(
152+
::Type{F},
153+
signbit::Bool, exponent_field::Integer, mantissa_field::Integer,
154+
) where {F<:IEEEFloat}
155+
T = uinttype(F)
156+
sign_and_exp = (T(signbit) << exponent_bits(F)) | T(exponent_field)
157+
ret = (sign_and_exp << significand_bits(F)) | T(mantissa_field)
158+
ret::T
159+
end
160+
161+
float_representation_of_infinity(::Type{F}, signbit::Bool) where {F<:IEEEFloat} =
162+
float_representation(F, signbit, exponent_raw_max(F), false)
163+
164+
float_representation_of_zero(::Type{F}, signbit::Bool) where {F<:IEEEFloat} =
165+
float_representation(F, signbit, false, false)
166+
167+
function float_representation_from_components(
168+
::Type{F},
169+
sign::Real, exp::Integer, mantissa::Integer,
170+
) where {F<:IEEEFloat}
171+
T = uinttype(F)
172+
sb = signbit(sign)
173+
174+
iszero(sign) && return float_representation_of_zero(F, sb)
175+
176+
normalized_exp = exp + significand_bits(F)
177+
178+
if exponent_max(F) < normalized_exp
179+
# overflow (infinity)
180+
float_representation_of_infinity(F, sb)
181+
elseif normalized_exp < true - exponent_bias(F)
182+
# underflow (subnormal or zero)
183+
ed = true - exponent_bias(F) - normalized_exp
184+
float_representation(F, sb, false, mantissa >> ed)
185+
else
186+
# normal: `true - exponent_bias(F) ≤ normalized_exp ≤ exponent_max(F)`
187+
mantissa_field = T(mantissa) & significand_mask(F) # clear the leading set bit
188+
e = normalized_exp + exponent_bias(F)
189+
float_representation(F, sb, e, mantissa_field)
190+
end
191+
end
192+
193+
float_from_components(
194+
::Type{F},
195+
sign::Real, exp::Integer, mantissa::Integer,
196+
) where {F<:IEEEFloat} =
197+
reinterpret(F, float_representation_from_components(F, sign, exp, mantissa))
198+
199+
# The input parameters represent the number `sign * 2^exp * mantissa`,
200+
# let's call it `n`. The sign is expected to be an integer between `-1`
201+
# and `1`, and the mantissa is expected to be as wide as the mantissa
202+
# of the floating-point type `F`, not counting the leading bit. Let's
203+
# call the number `x`.
204+
#
205+
# Returns the same value as `ldexp(sign * F(mantissa), exp)`
206+
float_from_components(
207+
::Type{F},
208+
sign::Real, exp::Integer, mantissa::Integer,
209+
) where {F<:AbstractFloat} =
210+
ldexp(sign * F(mantissa), exp)
211+
151212
## conversions to floating-point ##
152213

153214
# TODO: deprecate in 2.0

base/rational.jl

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -360,11 +360,10 @@ function rational_to_float_impl(
360360
T,
361361
RoundNearest,
362362
)
363-
mantissa = to_float(components.mantissa)
364-
365-
# TODO: `ldexp` could be replaced with a mere bit of bit twiddling
366-
# in the case of `Float16`, `Float32`, `Float64`
367-
ret = ldexp(s * mantissa, components.exponent)
363+
ret = float_from_components(
364+
typeof(to_float(false)),
365+
s, components.exponent, components.mantissa,
366+
)
368367

369368
# TODO: faster?
370369
if iszero(ret) | issubnormal(ret)
@@ -377,11 +376,10 @@ function rational_to_float_impl(
377376
T,
378377
RoundToZero,
379378
)
380-
mantissa = to_float(components.mantissa | !components.is_exact)
381-
382-
# TODO: `ldexp` could be replaced with a mere bit of bit
383-
# twiddling in the case of `Float16`, `Float32`, `Float64`
384-
ret = ldexp(s * mantissa, components.exponent)
379+
ret = float_from_components(
380+
typeof(to_float(false)),
381+
s, components.exponent, components.mantissa | !components.is_exact,
382+
)
385383
end
386384

387385
ret

0 commit comments

Comments
 (0)