Skip to content
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

implement rand(::BigFloat) (close #13948) #22720

Merged
merged 3 commits into from
Aug 23, 2017
Merged

implement rand(::BigFloat) (close #13948) #22720

merged 3 commits into from
Aug 23, 2017

Conversation

rfourquet
Copy link
Member

@rfourquet rfourquet commented Jul 9, 2017

This uses a similar method as for Float64: generate uniformly sufficiently many random bits to get a number x in [1, 2).
Then there are two simple possibilities (cf. this nice write-up):

  1. return x-1.0 : then one bit of precision is lost
  2. return rand(Bool) ? x/2 : x/2-0.5

For Float64, we do option 1) as dSFMT generates only 52 random bits per iteration, when Float64 has 53 bits of precision, and this is way faster (the cost of the branch of option 2 is non-negligible).
For BigFloat, the two options have similar performances (within few percents, and option 2) even is slightly faster than 1) for higher precisions), so I would favor this one. On the other hand, option 1) has the advantage that it would behave similarly to other floats when their precision is set to match (e.g. rand(BigFloat) would behave like rand(Float64) when precision(BigFloat) == 53). "RFC" until this is decided (option 1 is commented out here, if someone wants to play with it).

One possibility would be to have something along the lines of having rand(CloseOpen{T}) generate 1 random a float of type T with 1 bit less than the precision, rand(CloseOpenFull{T}) generate at full precision number, and rand(T) generate the best of the 2 options (1 for Float64 and 2 for BigFloat). This would incidentaly solve #16344, by allowing to get random Float64 at full precision (opt-in), which is not terribly slow after all: on my machine, this takes 14ns for full precision vs 5ns for 52 bits precision.

@rfourquet rfourquet added domain:randomness Random number generation and the Random stdlib domain:bignums BigInt and BigFloat labels Jul 9, 2017
base/random.jl Outdated
function rand!(r::AbstractRNG, A::AbstractArray, s::Union{Dict,Set,IntSet})
rand!(r::AbstractRNG, A::AbstractArray, ::Type{T}) where {T<:AbstractFloat} =
rand!(r, A, CloseOpen{T}())
rand!(A::AbstractArray, ::Type{T}) where {T<:AbstractFloat} = rand!(GLOBAL_RNG, A, T)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isn't this completely redundant with the more general version just above?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes thanks

@rfourquet rfourquet changed the title WIP: implement rand(::BigFloat) (close #13948) RFC: implement rand(::BigFloat) (close #13948) Jul 10, 2017
@mschauer
Copy link
Contributor

Isn't the branch optimized away if you do
x/2 - rand(Bool)*0.5 ?

@rfourquet
Copy link
Member Author

rfourquet commented Jul 11, 2017

Isn't the branch optimized away if you do x/2 - rand(Bool)*0.5 ?

Excellent, not directly (at least I don't see it) but appartently yes with 0.5*(x-rand(Bool)), which costs 8ns vs 5ns for rand(). I had tried with ifelse to avoid the branch, but had not got this speedup. Then it seems worthwhile to offer this full precision rand(Float).

For BigFloat, this (the cost of the branch) is a non-issue.

@rfourquet rfourquet changed the title RFC: implement rand(::BigFloat) (close #13948) implement rand(::BigFloat) (close #13948) Aug 18, 2017
@rfourquet
Copy link
Member Author

I decided to implement the full precision rand(BigFloat) by default, and to defer having an API to select full/not-full precision to another PR. I will merge in a couple of days if no objection.

(or complex numbers of those types). Random floating point numbers are generated uniformly
in ``[0, 1)``. As `BigInt` represents unbounded integers, the interval must be specified
(e.g. `rand(big(1:6))`).
[`Float16`](@ref), [`Float32`](@ref), [`Float64`](@ref), [`Float64`](@ref),[`Bool`](@ref),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is the Float64 you added here supposed to be BigFloat?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oups yes! (rebase mistake)

@rfourquet
Copy link
Member Author

The Travis and circleci failures have to do RowVector (inferred return type), it's an already seen failure, and the appveyor failure has to do with "codegen"; so looks unrelated.

@rfourquet rfourquet merged commit ebc4ade into master Aug 23, 2017
@rfourquet rfourquet deleted the rf/rand-BigFloat branch August 23, 2017 14:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
domain:bignums BigInt and BigFloat domain:randomness Random number generation and the Random stdlib
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants