-
-
Notifications
You must be signed in to change notification settings - Fork 5.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
BigInt to Float conversions are unnecessarily slow #31293
Comments
Yikes! |
I am interested in solving this issue. I experimented with |
Great! It's a little bit tricky (which is why I suspect GMP hasn't implemented it), but one approach is:
|
I came up with this implementation function proposed_Float64(x::BigInt)
x == 0.0 && return 0.0
if abs(x.size) > 16
temp = Inf
elseif abs(x.size) == 1
temp = Float64(unsafe_load(x.d))
else
temp = Float64((UInt128(unsafe_load(x.d,abs(x.size))) << 64)
+unsafe_load(x.d, (abs(x.size)-1)))
temp *= 2.0^((abs(x.size)-2)*64)
end
signbit(x.size) && return -temp
return temp
end By using current julia> d = big"2"^300 + 64
2037035976334486086268445688409378161051468393665936250636140449354381299763336706183397440
julia> @btime proposed_Float64(d)
26.645 ns (0 allocations: 0 bytes)
2.037035976334486e90
julia> @btime Float64(d)
281.984 ns (7 allocations: 168 bytes)
2.037035976334486e90 Any suggestions? @simonbyrne |
There are a couple of issues:
|
This implementation solves the double rounding problem. I still have to clean the code and implement for 32 bits. I just wanted to know, if this type of approach is okay or not? Also in 32 bit implementation should I just use function Float64(n::BigInt)
n == 0 && return 0.0
if Int == Int64
if abs(x.size) > 16
temp = Inf
elseif abs(x.size) == 1
temp = Float64(unsafe_load(x.d))
else
y1 = unsafe_load(x.d, x.size)
n = 64 - leading_zeros(y1)
if n > 53
y = (y1 >> (n-54))
y = (y + 1) >> 1
y &= ~UInt64(trailing_zeros(x) == (n-54 + (x.size-1)*64))
d = (n+1021) << 52
temp = reinterpret(Float64, d+y)
temp = ldexp(temp, (x.size - 1)*64)
else
y = y1 << (54 - n) + unsafe_load(x.d, x.size-1) >> (10 + n)
y = (y + 1) >> 1
y &= ~UInt64(trailing_zeros(x) == (10+n + (x.size-2)*64))
d = (n+1021) << 52
temp = reinterpret(Float64, d+y)
temp = ldexp(temp, (x.size - 1)*64)
end
end
signbit(x.size) && return -temp
return temp
end
#TODO: implement for 32 bit machine
end |
Something along those lines was what I had in mind. Did you want to open a draft pull request? It might be easier to provide feedback on that. |
This could probably be done even more efficiently by doing bit-shifting on the limbs.
The text was updated successfully, but these errors were encountered: