Generate uniformly random float which can return all possible values










8















An easy way to generate a random float64 in [0,1) is by generating a uniformly random int in [0,2⁵³) and dividing it by 2⁵³. This is essentially what rand.Float64() is doing.
However, not all possible float64 values between 0 and 1 can be generated this way: if the value is lower than 2⁻⁴ for example, the 4 last bits of the significand are always going to be 0. Or, put more simply, the naive method always returns multiples of 2⁻⁵³, and not all floating point numbers between 0 and 1 are multiples of 2⁻⁵³.



How do you generate a uniformly random float64 such as every possible value has a chance of being returned? (Here, uniformly random means over the real interval [0,1): conceptually, I want to pick a uniformly random real number between 0 and 1 and return the closest float.)



For context, I need this because I'm implementing this paper and the assumption "all possible values between 0 and 1 are represented" is essential for the result to hold.










share|improve this question
























  • rand.Float64() is probably the closest in-built way of doing it golang.org/pkg/math/rand/#Rand.Float64

    – Carlos Gonzalez
    Nov 13 '18 at 9:00







  • 1





    No, rand.Float64() does it the naive way and doesn't return every possible value. I edited the question to add a link.

    – Ted
    Nov 13 '18 at 9:08











  • with the chance of getting 1 being 1/2⁵³ i don't think you need to worry about it, if you do worry about it the docs you linked under cincenzo's answer explain how to fix it. so you can implement rand float 64 yourself

    – Pizza lord
    Nov 13 '18 at 9:13






  • 1





    You probably have to implement this yourself. mumble.net/~campbell/2014/04/28 might be a starting point.

    – Ralf Stubner
    Nov 13 '18 at 9:13






  • 1





    The paper tells you what to generate: “A uniform distribution over D ∩ (0, 1) can be generated by independently sampling an exponent (from the geometric distribution with parameter .5) and a significand (by drawing a uniform string from 0, 1⁵²).” That omits discussion of subnormals. I suspect covering the normals suffices for their purposes, but completing the geometric distribution by duplicating the probability for the least normal exponent and the subnormal values would fit nicely. (The probability of each floating-point number in [0, 1) would be proportional to its ULP.)

    – Eric Postpischil
    Nov 15 '18 at 2:13
















8















An easy way to generate a random float64 in [0,1) is by generating a uniformly random int in [0,2⁵³) and dividing it by 2⁵³. This is essentially what rand.Float64() is doing.
However, not all possible float64 values between 0 and 1 can be generated this way: if the value is lower than 2⁻⁴ for example, the 4 last bits of the significand are always going to be 0. Or, put more simply, the naive method always returns multiples of 2⁻⁵³, and not all floating point numbers between 0 and 1 are multiples of 2⁻⁵³.



How do you generate a uniformly random float64 such as every possible value has a chance of being returned? (Here, uniformly random means over the real interval [0,1): conceptually, I want to pick a uniformly random real number between 0 and 1 and return the closest float.)



For context, I need this because I'm implementing this paper and the assumption "all possible values between 0 and 1 are represented" is essential for the result to hold.










share|improve this question
























  • rand.Float64() is probably the closest in-built way of doing it golang.org/pkg/math/rand/#Rand.Float64

    – Carlos Gonzalez
    Nov 13 '18 at 9:00







  • 1





    No, rand.Float64() does it the naive way and doesn't return every possible value. I edited the question to add a link.

    – Ted
    Nov 13 '18 at 9:08











  • with the chance of getting 1 being 1/2⁵³ i don't think you need to worry about it, if you do worry about it the docs you linked under cincenzo's answer explain how to fix it. so you can implement rand float 64 yourself

    – Pizza lord
    Nov 13 '18 at 9:13






  • 1





    You probably have to implement this yourself. mumble.net/~campbell/2014/04/28 might be a starting point.

    – Ralf Stubner
    Nov 13 '18 at 9:13






  • 1





    The paper tells you what to generate: “A uniform distribution over D ∩ (0, 1) can be generated by independently sampling an exponent (from the geometric distribution with parameter .5) and a significand (by drawing a uniform string from 0, 1⁵²).” That omits discussion of subnormals. I suspect covering the normals suffices for their purposes, but completing the geometric distribution by duplicating the probability for the least normal exponent and the subnormal values would fit nicely. (The probability of each floating-point number in [0, 1) would be proportional to its ULP.)

    – Eric Postpischil
    Nov 15 '18 at 2:13














8












8








8


1






An easy way to generate a random float64 in [0,1) is by generating a uniformly random int in [0,2⁵³) and dividing it by 2⁵³. This is essentially what rand.Float64() is doing.
However, not all possible float64 values between 0 and 1 can be generated this way: if the value is lower than 2⁻⁴ for example, the 4 last bits of the significand are always going to be 0. Or, put more simply, the naive method always returns multiples of 2⁻⁵³, and not all floating point numbers between 0 and 1 are multiples of 2⁻⁵³.



How do you generate a uniformly random float64 such as every possible value has a chance of being returned? (Here, uniformly random means over the real interval [0,1): conceptually, I want to pick a uniformly random real number between 0 and 1 and return the closest float.)



For context, I need this because I'm implementing this paper and the assumption "all possible values between 0 and 1 are represented" is essential for the result to hold.










share|improve this question
















An easy way to generate a random float64 in [0,1) is by generating a uniformly random int in [0,2⁵³) and dividing it by 2⁵³. This is essentially what rand.Float64() is doing.
However, not all possible float64 values between 0 and 1 can be generated this way: if the value is lower than 2⁻⁴ for example, the 4 last bits of the significand are always going to be 0. Or, put more simply, the naive method always returns multiples of 2⁻⁵³, and not all floating point numbers between 0 and 1 are multiples of 2⁻⁵³.



How do you generate a uniformly random float64 such as every possible value has a chance of being returned? (Here, uniformly random means over the real interval [0,1): conceptually, I want to pick a uniformly random real number between 0 and 1 and return the closest float.)



For context, I need this because I'm implementing this paper and the assumption "all possible values between 0 and 1 are represented" is essential for the result to hold.







go random floating-point






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 14 '18 at 7:33







Ted

















asked Nov 13 '18 at 8:52









TedTed

443414




443414












  • rand.Float64() is probably the closest in-built way of doing it golang.org/pkg/math/rand/#Rand.Float64

    – Carlos Gonzalez
    Nov 13 '18 at 9:00







  • 1





    No, rand.Float64() does it the naive way and doesn't return every possible value. I edited the question to add a link.

    – Ted
    Nov 13 '18 at 9:08











  • with the chance of getting 1 being 1/2⁵³ i don't think you need to worry about it, if you do worry about it the docs you linked under cincenzo's answer explain how to fix it. so you can implement rand float 64 yourself

    – Pizza lord
    Nov 13 '18 at 9:13






  • 1





    You probably have to implement this yourself. mumble.net/~campbell/2014/04/28 might be a starting point.

    – Ralf Stubner
    Nov 13 '18 at 9:13






  • 1





    The paper tells you what to generate: “A uniform distribution over D ∩ (0, 1) can be generated by independently sampling an exponent (from the geometric distribution with parameter .5) and a significand (by drawing a uniform string from 0, 1⁵²).” That omits discussion of subnormals. I suspect covering the normals suffices for their purposes, but completing the geometric distribution by duplicating the probability for the least normal exponent and the subnormal values would fit nicely. (The probability of each floating-point number in [0, 1) would be proportional to its ULP.)

    – Eric Postpischil
    Nov 15 '18 at 2:13


















  • rand.Float64() is probably the closest in-built way of doing it golang.org/pkg/math/rand/#Rand.Float64

    – Carlos Gonzalez
    Nov 13 '18 at 9:00







  • 1





    No, rand.Float64() does it the naive way and doesn't return every possible value. I edited the question to add a link.

    – Ted
    Nov 13 '18 at 9:08











  • with the chance of getting 1 being 1/2⁵³ i don't think you need to worry about it, if you do worry about it the docs you linked under cincenzo's answer explain how to fix it. so you can implement rand float 64 yourself

    – Pizza lord
    Nov 13 '18 at 9:13






  • 1





    You probably have to implement this yourself. mumble.net/~campbell/2014/04/28 might be a starting point.

    – Ralf Stubner
    Nov 13 '18 at 9:13






  • 1





    The paper tells you what to generate: “A uniform distribution over D ∩ (0, 1) can be generated by independently sampling an exponent (from the geometric distribution with parameter .5) and a significand (by drawing a uniform string from 0, 1⁵²).” That omits discussion of subnormals. I suspect covering the normals suffices for their purposes, but completing the geometric distribution by duplicating the probability for the least normal exponent and the subnormal values would fit nicely. (The probability of each floating-point number in [0, 1) would be proportional to its ULP.)

    – Eric Postpischil
    Nov 15 '18 at 2:13

















rand.Float64() is probably the closest in-built way of doing it golang.org/pkg/math/rand/#Rand.Float64

– Carlos Gonzalez
Nov 13 '18 at 9:00






rand.Float64() is probably the closest in-built way of doing it golang.org/pkg/math/rand/#Rand.Float64

– Carlos Gonzalez
Nov 13 '18 at 9:00





1




1





No, rand.Float64() does it the naive way and doesn't return every possible value. I edited the question to add a link.

– Ted
Nov 13 '18 at 9:08





No, rand.Float64() does it the naive way and doesn't return every possible value. I edited the question to add a link.

– Ted
Nov 13 '18 at 9:08













with the chance of getting 1 being 1/2⁵³ i don't think you need to worry about it, if you do worry about it the docs you linked under cincenzo's answer explain how to fix it. so you can implement rand float 64 yourself

– Pizza lord
Nov 13 '18 at 9:13





with the chance of getting 1 being 1/2⁵³ i don't think you need to worry about it, if you do worry about it the docs you linked under cincenzo's answer explain how to fix it. so you can implement rand float 64 yourself

– Pizza lord
Nov 13 '18 at 9:13




1




1





You probably have to implement this yourself. mumble.net/~campbell/2014/04/28 might be a starting point.

– Ralf Stubner
Nov 13 '18 at 9:13





You probably have to implement this yourself. mumble.net/~campbell/2014/04/28 might be a starting point.

– Ralf Stubner
Nov 13 '18 at 9:13




1




1





The paper tells you what to generate: “A uniform distribution over D ∩ (0, 1) can be generated by independently sampling an exponent (from the geometric distribution with parameter .5) and a significand (by drawing a uniform string from 0, 1⁵²).” That omits discussion of subnormals. I suspect covering the normals suffices for their purposes, but completing the geometric distribution by duplicating the probability for the least normal exponent and the subnormal values would fit nicely. (The probability of each floating-point number in [0, 1) would be proportional to its ULP.)

– Eric Postpischil
Nov 15 '18 at 2:13






The paper tells you what to generate: “A uniform distribution over D ∩ (0, 1) can be generated by independently sampling an exponent (from the geometric distribution with parameter .5) and a significand (by drawing a uniform string from 0, 1⁵²).” That omits discussion of subnormals. I suspect covering the normals suffices for their purposes, but completing the geometric distribution by duplicating the probability for the least normal exponent and the subnormal values would fit nicely. (The probability of each floating-point number in [0, 1) would be proportional to its ULP.)

– Eric Postpischil
Nov 15 '18 at 2:13













5 Answers
5






active

oldest

votes


















2














Because the binary64 floating point numbers are not uniformly spaced, you cannot generate a uniform distribution which can return all possible values less that 1.



If you omit the requirement uniform you have to generate all representable multiples of the smallest positive denormal number 2^(-1074)and zero.






share|improve this answer























  • I don't understand this comment. Essentially, I want do as if I were selecting a real number uniformly randomly between 0 and 1 and rounding it to the next float. I think Severin's answer is what I'm looking for. I'll implement it in Go.

    – Ted
    Nov 13 '18 at 15:09











  • You should add this to your question, but be aware that your mapping can generate 1 for values in the interval (1-2^(-53), 1)

    – gammatester
    Nov 13 '18 at 15:40


















2














Porting this code (suggested in Severin's answer) is a possible option.



I think that it is equivalent to first generate the significand bits (by generating a random float in [1,2)), and then choose the exponent from a geometric distribution (it has a 0.5 chance of being -1, 0.25 of being -2, etc.).



// uniform returns a uniformly random float in [0,1).
func uniform() float64
sig := rand.Uint64() % (1 << 52)
return (1 + float64(i)/(1<<52)) / math.Pow(2, geometric())


// geometric returns a number picked from a geometric
// distribution of parameter 0.5.
func geometric() float64
b := 1
for rand.Uint64()%2 == 0
b++

return b



We can probably make geometric() faster by using one of the LeadingZeros* functions from the bits package instead of doing one coin flip per bit.






share|improve this answer























  • If you're going to port code directly, things would depend on ldexp() implementation. I quickly looked through Go runtime and glibc implementation, and there are quite some differences to my surprise.

    – Severin Pappadeux
    Nov 14 '18 at 0:50











  • Yes, that's why I'm taking another approach for the implementation. I think both are conceptually equivalent (but would be happy to be proven wrong).

    – Ted
    Nov 14 '18 at 7:31











  • just updated my answer with another useful link

    – Severin Pappadeux
    Dec 3 '18 at 16:27


















2














Well, standard way, I believe, is to generate up to 1074bits integer and map it to the double. Beware, that your RNG should have internal state at least 1074bits long.



Reference implementation: http://xoshiro.di.unimi.it/random_real.c



Discussion about it: http://xoshiro.di.unimi.it/



Another good link: https://lemire.me/blog/2017/02/28/how-many-floating-point-numbers-are-in-the-interval-01/






share|improve this answer

























  • (a) That is a way, not “the standard” way. (b) Its range is [0, 1], but the question asks for [0, 1). It does mention the range can be reduced by rejection sampling (retry if the result is 1). (c) It generates 1074 only conceptually; in practice it uses many smaller bits in almost all cases.

    – Eric Postpischil
    Nov 13 '18 at 16:35











  • @EricPostpischil (a) Doesn't seems to be a better way. (b) yep, rejection comes to rescue, I believe it is mention in comments. (c) yes, thank you, I corrected the answer.

    – Severin Pappadeux
    Nov 13 '18 at 18:16


















1














You could use brute-force rejection sampling by generating 16 random bytes and using it only if it's a valid float64 in [0,1). This approach should give you a normal distribution of all values in that range with performance not much worse than other strategies based on simple benchmarking.



For example (Go Playground):



import "math/rand"

func randFloat64() float64
for
f := math.Float64frombits(rand.Uint64())
if f >= 0 && f < 1.0
return f





If performance is critical then you could build an enormous lookup table containing only the valid numbers and choose a random location in the table. The table could be generated ahead of time in a similar fashion as above, by enumerating the bitfield and storing only valid numbers.






share|improve this answer

























  • Thanks — but this generates a uniform distribution over the possible elements, not over the real interval. I clarified the question.

    – Ted
    Nov 14 '18 at 7:35


















-1














You can use rand Float64 function to return float in the [0, 1) range:



package main

import (
"fmt"
"math/rand"
)

func main()
fmt.Println(rand.Float64())



From the docs:




Float64 returns, as a float64, a pseudo-random number in [0.0,1.0) from the default Source.







share|improve this answer























  • Precisely, no: golang.org/src/math/rand/rand.go?s=5359:5391#L168 doesn't return all possible values.

    – Ted
    Nov 13 '18 at 9:06











  • From the source comment: "Instead of that, if we round up to 1, just try again. Getting 1 only happens 1/2⁵³ of the time, so most clients will not observe it anyway.". They say they taken into account this.

    – Vincenzo Maggio
    Nov 13 '18 at 9:08












  • That's not the problem. The problem is that this code only returns multiples of 2⁻⁵³. Not all floating-point numbers between 0 and 1 are multiples of 2⁻⁵³, so you don't return all of them this way.

    – Ted
    Nov 13 '18 at 9:10











  • Listen, here's a discussion with even Russ Cox itself intervining: github.com/golang/go/issues/12290 saying this is not a huge problem. Thanks for the downvote.

    – Vincenzo Maggio
    Nov 13 '18 at 9:14











  • I added a comment explaining why I have a good reason not to use the code from the standard library. Thanks for making me notice that the rationale for my question was unclear! =)

    – Ted
    Nov 13 '18 at 9:20










Your Answer






StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);













draft saved

draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53277105%2fgenerate-uniformly-random-float-which-can-return-all-possible-values%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown

























5 Answers
5






active

oldest

votes








5 Answers
5






active

oldest

votes









active

oldest

votes






active

oldest

votes









2














Because the binary64 floating point numbers are not uniformly spaced, you cannot generate a uniform distribution which can return all possible values less that 1.



If you omit the requirement uniform you have to generate all representable multiples of the smallest positive denormal number 2^(-1074)and zero.






share|improve this answer























  • I don't understand this comment. Essentially, I want do as if I were selecting a real number uniformly randomly between 0 and 1 and rounding it to the next float. I think Severin's answer is what I'm looking for. I'll implement it in Go.

    – Ted
    Nov 13 '18 at 15:09











  • You should add this to your question, but be aware that your mapping can generate 1 for values in the interval (1-2^(-53), 1)

    – gammatester
    Nov 13 '18 at 15:40















2














Because the binary64 floating point numbers are not uniformly spaced, you cannot generate a uniform distribution which can return all possible values less that 1.



If you omit the requirement uniform you have to generate all representable multiples of the smallest positive denormal number 2^(-1074)and zero.






share|improve this answer























  • I don't understand this comment. Essentially, I want do as if I were selecting a real number uniformly randomly between 0 and 1 and rounding it to the next float. I think Severin's answer is what I'm looking for. I'll implement it in Go.

    – Ted
    Nov 13 '18 at 15:09











  • You should add this to your question, but be aware that your mapping can generate 1 for values in the interval (1-2^(-53), 1)

    – gammatester
    Nov 13 '18 at 15:40













2












2








2







Because the binary64 floating point numbers are not uniformly spaced, you cannot generate a uniform distribution which can return all possible values less that 1.



If you omit the requirement uniform you have to generate all representable multiples of the smallest positive denormal number 2^(-1074)and zero.






share|improve this answer













Because the binary64 floating point numbers are not uniformly spaced, you cannot generate a uniform distribution which can return all possible values less that 1.



If you omit the requirement uniform you have to generate all representable multiples of the smallest positive denormal number 2^(-1074)and zero.







share|improve this answer












share|improve this answer



share|improve this answer










answered Nov 13 '18 at 9:42









gammatestergammatester

9181712




9181712












  • I don't understand this comment. Essentially, I want do as if I were selecting a real number uniformly randomly between 0 and 1 and rounding it to the next float. I think Severin's answer is what I'm looking for. I'll implement it in Go.

    – Ted
    Nov 13 '18 at 15:09











  • You should add this to your question, but be aware that your mapping can generate 1 for values in the interval (1-2^(-53), 1)

    – gammatester
    Nov 13 '18 at 15:40

















  • I don't understand this comment. Essentially, I want do as if I were selecting a real number uniformly randomly between 0 and 1 and rounding it to the next float. I think Severin's answer is what I'm looking for. I'll implement it in Go.

    – Ted
    Nov 13 '18 at 15:09











  • You should add this to your question, but be aware that your mapping can generate 1 for values in the interval (1-2^(-53), 1)

    – gammatester
    Nov 13 '18 at 15:40
















I don't understand this comment. Essentially, I want do as if I were selecting a real number uniformly randomly between 0 and 1 and rounding it to the next float. I think Severin's answer is what I'm looking for. I'll implement it in Go.

– Ted
Nov 13 '18 at 15:09





I don't understand this comment. Essentially, I want do as if I were selecting a real number uniformly randomly between 0 and 1 and rounding it to the next float. I think Severin's answer is what I'm looking for. I'll implement it in Go.

– Ted
Nov 13 '18 at 15:09













You should add this to your question, but be aware that your mapping can generate 1 for values in the interval (1-2^(-53), 1)

– gammatester
Nov 13 '18 at 15:40





You should add this to your question, but be aware that your mapping can generate 1 for values in the interval (1-2^(-53), 1)

– gammatester
Nov 13 '18 at 15:40













2














Porting this code (suggested in Severin's answer) is a possible option.



I think that it is equivalent to first generate the significand bits (by generating a random float in [1,2)), and then choose the exponent from a geometric distribution (it has a 0.5 chance of being -1, 0.25 of being -2, etc.).



// uniform returns a uniformly random float in [0,1).
func uniform() float64
sig := rand.Uint64() % (1 << 52)
return (1 + float64(i)/(1<<52)) / math.Pow(2, geometric())


// geometric returns a number picked from a geometric
// distribution of parameter 0.5.
func geometric() float64
b := 1
for rand.Uint64()%2 == 0
b++

return b



We can probably make geometric() faster by using one of the LeadingZeros* functions from the bits package instead of doing one coin flip per bit.






share|improve this answer























  • If you're going to port code directly, things would depend on ldexp() implementation. I quickly looked through Go runtime and glibc implementation, and there are quite some differences to my surprise.

    – Severin Pappadeux
    Nov 14 '18 at 0:50











  • Yes, that's why I'm taking another approach for the implementation. I think both are conceptually equivalent (but would be happy to be proven wrong).

    – Ted
    Nov 14 '18 at 7:31











  • just updated my answer with another useful link

    – Severin Pappadeux
    Dec 3 '18 at 16:27















2














Porting this code (suggested in Severin's answer) is a possible option.



I think that it is equivalent to first generate the significand bits (by generating a random float in [1,2)), and then choose the exponent from a geometric distribution (it has a 0.5 chance of being -1, 0.25 of being -2, etc.).



// uniform returns a uniformly random float in [0,1).
func uniform() float64
sig := rand.Uint64() % (1 << 52)
return (1 + float64(i)/(1<<52)) / math.Pow(2, geometric())


// geometric returns a number picked from a geometric
// distribution of parameter 0.5.
func geometric() float64
b := 1
for rand.Uint64()%2 == 0
b++

return b



We can probably make geometric() faster by using one of the LeadingZeros* functions from the bits package instead of doing one coin flip per bit.






share|improve this answer























  • If you're going to port code directly, things would depend on ldexp() implementation. I quickly looked through Go runtime and glibc implementation, and there are quite some differences to my surprise.

    – Severin Pappadeux
    Nov 14 '18 at 0:50











  • Yes, that's why I'm taking another approach for the implementation. I think both are conceptually equivalent (but would be happy to be proven wrong).

    – Ted
    Nov 14 '18 at 7:31











  • just updated my answer with another useful link

    – Severin Pappadeux
    Dec 3 '18 at 16:27













2












2








2







Porting this code (suggested in Severin's answer) is a possible option.



I think that it is equivalent to first generate the significand bits (by generating a random float in [1,2)), and then choose the exponent from a geometric distribution (it has a 0.5 chance of being -1, 0.25 of being -2, etc.).



// uniform returns a uniformly random float in [0,1).
func uniform() float64
sig := rand.Uint64() % (1 << 52)
return (1 + float64(i)/(1<<52)) / math.Pow(2, geometric())


// geometric returns a number picked from a geometric
// distribution of parameter 0.5.
func geometric() float64
b := 1
for rand.Uint64()%2 == 0
b++

return b



We can probably make geometric() faster by using one of the LeadingZeros* functions from the bits package instead of doing one coin flip per bit.






share|improve this answer













Porting this code (suggested in Severin's answer) is a possible option.



I think that it is equivalent to first generate the significand bits (by generating a random float in [1,2)), and then choose the exponent from a geometric distribution (it has a 0.5 chance of being -1, 0.25 of being -2, etc.).



// uniform returns a uniformly random float in [0,1).
func uniform() float64
sig := rand.Uint64() % (1 << 52)
return (1 + float64(i)/(1<<52)) / math.Pow(2, geometric())


// geometric returns a number picked from a geometric
// distribution of parameter 0.5.
func geometric() float64
b := 1
for rand.Uint64()%2 == 0
b++

return b



We can probably make geometric() faster by using one of the LeadingZeros* functions from the bits package instead of doing one coin flip per bit.







share|improve this answer












share|improve this answer



share|improve this answer










answered Nov 13 '18 at 17:37









TedTed

443414




443414












  • If you're going to port code directly, things would depend on ldexp() implementation. I quickly looked through Go runtime and glibc implementation, and there are quite some differences to my surprise.

    – Severin Pappadeux
    Nov 14 '18 at 0:50











  • Yes, that's why I'm taking another approach for the implementation. I think both are conceptually equivalent (but would be happy to be proven wrong).

    – Ted
    Nov 14 '18 at 7:31











  • just updated my answer with another useful link

    – Severin Pappadeux
    Dec 3 '18 at 16:27

















  • If you're going to port code directly, things would depend on ldexp() implementation. I quickly looked through Go runtime and glibc implementation, and there are quite some differences to my surprise.

    – Severin Pappadeux
    Nov 14 '18 at 0:50











  • Yes, that's why I'm taking another approach for the implementation. I think both are conceptually equivalent (but would be happy to be proven wrong).

    – Ted
    Nov 14 '18 at 7:31











  • just updated my answer with another useful link

    – Severin Pappadeux
    Dec 3 '18 at 16:27
















If you're going to port code directly, things would depend on ldexp() implementation. I quickly looked through Go runtime and glibc implementation, and there are quite some differences to my surprise.

– Severin Pappadeux
Nov 14 '18 at 0:50





If you're going to port code directly, things would depend on ldexp() implementation. I quickly looked through Go runtime and glibc implementation, and there are quite some differences to my surprise.

– Severin Pappadeux
Nov 14 '18 at 0:50













Yes, that's why I'm taking another approach for the implementation. I think both are conceptually equivalent (but would be happy to be proven wrong).

– Ted
Nov 14 '18 at 7:31





Yes, that's why I'm taking another approach for the implementation. I think both are conceptually equivalent (but would be happy to be proven wrong).

– Ted
Nov 14 '18 at 7:31













just updated my answer with another useful link

– Severin Pappadeux
Dec 3 '18 at 16:27





just updated my answer with another useful link

– Severin Pappadeux
Dec 3 '18 at 16:27











2














Well, standard way, I believe, is to generate up to 1074bits integer and map it to the double. Beware, that your RNG should have internal state at least 1074bits long.



Reference implementation: http://xoshiro.di.unimi.it/random_real.c



Discussion about it: http://xoshiro.di.unimi.it/



Another good link: https://lemire.me/blog/2017/02/28/how-many-floating-point-numbers-are-in-the-interval-01/






share|improve this answer

























  • (a) That is a way, not “the standard” way. (b) Its range is [0, 1], but the question asks for [0, 1). It does mention the range can be reduced by rejection sampling (retry if the result is 1). (c) It generates 1074 only conceptually; in practice it uses many smaller bits in almost all cases.

    – Eric Postpischil
    Nov 13 '18 at 16:35











  • @EricPostpischil (a) Doesn't seems to be a better way. (b) yep, rejection comes to rescue, I believe it is mention in comments. (c) yes, thank you, I corrected the answer.

    – Severin Pappadeux
    Nov 13 '18 at 18:16















2














Well, standard way, I believe, is to generate up to 1074bits integer and map it to the double. Beware, that your RNG should have internal state at least 1074bits long.



Reference implementation: http://xoshiro.di.unimi.it/random_real.c



Discussion about it: http://xoshiro.di.unimi.it/



Another good link: https://lemire.me/blog/2017/02/28/how-many-floating-point-numbers-are-in-the-interval-01/






share|improve this answer

























  • (a) That is a way, not “the standard” way. (b) Its range is [0, 1], but the question asks for [0, 1). It does mention the range can be reduced by rejection sampling (retry if the result is 1). (c) It generates 1074 only conceptually; in practice it uses many smaller bits in almost all cases.

    – Eric Postpischil
    Nov 13 '18 at 16:35











  • @EricPostpischil (a) Doesn't seems to be a better way. (b) yep, rejection comes to rescue, I believe it is mention in comments. (c) yes, thank you, I corrected the answer.

    – Severin Pappadeux
    Nov 13 '18 at 18:16













2












2








2







Well, standard way, I believe, is to generate up to 1074bits integer and map it to the double. Beware, that your RNG should have internal state at least 1074bits long.



Reference implementation: http://xoshiro.di.unimi.it/random_real.c



Discussion about it: http://xoshiro.di.unimi.it/



Another good link: https://lemire.me/blog/2017/02/28/how-many-floating-point-numbers-are-in-the-interval-01/






share|improve this answer















Well, standard way, I believe, is to generate up to 1074bits integer and map it to the double. Beware, that your RNG should have internal state at least 1074bits long.



Reference implementation: http://xoshiro.di.unimi.it/random_real.c



Discussion about it: http://xoshiro.di.unimi.it/



Another good link: https://lemire.me/blog/2017/02/28/how-many-floating-point-numbers-are-in-the-interval-01/







share|improve this answer














share|improve this answer



share|improve this answer








edited Dec 3 '18 at 16:27

























answered Nov 13 '18 at 14:30









Severin PappadeuxSeverin Pappadeux

9,49121432




9,49121432












  • (a) That is a way, not “the standard” way. (b) Its range is [0, 1], but the question asks for [0, 1). It does mention the range can be reduced by rejection sampling (retry if the result is 1). (c) It generates 1074 only conceptually; in practice it uses many smaller bits in almost all cases.

    – Eric Postpischil
    Nov 13 '18 at 16:35











  • @EricPostpischil (a) Doesn't seems to be a better way. (b) yep, rejection comes to rescue, I believe it is mention in comments. (c) yes, thank you, I corrected the answer.

    – Severin Pappadeux
    Nov 13 '18 at 18:16

















  • (a) That is a way, not “the standard” way. (b) Its range is [0, 1], but the question asks for [0, 1). It does mention the range can be reduced by rejection sampling (retry if the result is 1). (c) It generates 1074 only conceptually; in practice it uses many smaller bits in almost all cases.

    – Eric Postpischil
    Nov 13 '18 at 16:35











  • @EricPostpischil (a) Doesn't seems to be a better way. (b) yep, rejection comes to rescue, I believe it is mention in comments. (c) yes, thank you, I corrected the answer.

    – Severin Pappadeux
    Nov 13 '18 at 18:16
















(a) That is a way, not “the standard” way. (b) Its range is [0, 1], but the question asks for [0, 1). It does mention the range can be reduced by rejection sampling (retry if the result is 1). (c) It generates 1074 only conceptually; in practice it uses many smaller bits in almost all cases.

– Eric Postpischil
Nov 13 '18 at 16:35





(a) That is a way, not “the standard” way. (b) Its range is [0, 1], but the question asks for [0, 1). It does mention the range can be reduced by rejection sampling (retry if the result is 1). (c) It generates 1074 only conceptually; in practice it uses many smaller bits in almost all cases.

– Eric Postpischil
Nov 13 '18 at 16:35













@EricPostpischil (a) Doesn't seems to be a better way. (b) yep, rejection comes to rescue, I believe it is mention in comments. (c) yes, thank you, I corrected the answer.

– Severin Pappadeux
Nov 13 '18 at 18:16





@EricPostpischil (a) Doesn't seems to be a better way. (b) yep, rejection comes to rescue, I believe it is mention in comments. (c) yes, thank you, I corrected the answer.

– Severin Pappadeux
Nov 13 '18 at 18:16











1














You could use brute-force rejection sampling by generating 16 random bytes and using it only if it's a valid float64 in [0,1). This approach should give you a normal distribution of all values in that range with performance not much worse than other strategies based on simple benchmarking.



For example (Go Playground):



import "math/rand"

func randFloat64() float64
for
f := math.Float64frombits(rand.Uint64())
if f >= 0 && f < 1.0
return f





If performance is critical then you could build an enormous lookup table containing only the valid numbers and choose a random location in the table. The table could be generated ahead of time in a similar fashion as above, by enumerating the bitfield and storing only valid numbers.






share|improve this answer

























  • Thanks — but this generates a uniform distribution over the possible elements, not over the real interval. I clarified the question.

    – Ted
    Nov 14 '18 at 7:35















1














You could use brute-force rejection sampling by generating 16 random bytes and using it only if it's a valid float64 in [0,1). This approach should give you a normal distribution of all values in that range with performance not much worse than other strategies based on simple benchmarking.



For example (Go Playground):



import "math/rand"

func randFloat64() float64
for
f := math.Float64frombits(rand.Uint64())
if f >= 0 && f < 1.0
return f





If performance is critical then you could build an enormous lookup table containing only the valid numbers and choose a random location in the table. The table could be generated ahead of time in a similar fashion as above, by enumerating the bitfield and storing only valid numbers.






share|improve this answer

























  • Thanks — but this generates a uniform distribution over the possible elements, not over the real interval. I clarified the question.

    – Ted
    Nov 14 '18 at 7:35













1












1








1







You could use brute-force rejection sampling by generating 16 random bytes and using it only if it's a valid float64 in [0,1). This approach should give you a normal distribution of all values in that range with performance not much worse than other strategies based on simple benchmarking.



For example (Go Playground):



import "math/rand"

func randFloat64() float64
for
f := math.Float64frombits(rand.Uint64())
if f >= 0 && f < 1.0
return f





If performance is critical then you could build an enormous lookup table containing only the valid numbers and choose a random location in the table. The table could be generated ahead of time in a similar fashion as above, by enumerating the bitfield and storing only valid numbers.






share|improve this answer















You could use brute-force rejection sampling by generating 16 random bytes and using it only if it's a valid float64 in [0,1). This approach should give you a normal distribution of all values in that range with performance not much worse than other strategies based on simple benchmarking.



For example (Go Playground):



import "math/rand"

func randFloat64() float64
for
f := math.Float64frombits(rand.Uint64())
if f >= 0 && f < 1.0
return f





If performance is critical then you could build an enormous lookup table containing only the valid numbers and choose a random location in the table. The table could be generated ahead of time in a similar fashion as above, by enumerating the bitfield and storing only valid numbers.







share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 13 '18 at 20:37

























answered Nov 13 '18 at 18:12









maericsmaerics

105k29202249




105k29202249












  • Thanks — but this generates a uniform distribution over the possible elements, not over the real interval. I clarified the question.

    – Ted
    Nov 14 '18 at 7:35

















  • Thanks — but this generates a uniform distribution over the possible elements, not over the real interval. I clarified the question.

    – Ted
    Nov 14 '18 at 7:35
















Thanks — but this generates a uniform distribution over the possible elements, not over the real interval. I clarified the question.

– Ted
Nov 14 '18 at 7:35





Thanks — but this generates a uniform distribution over the possible elements, not over the real interval. I clarified the question.

– Ted
Nov 14 '18 at 7:35











-1














You can use rand Float64 function to return float in the [0, 1) range:



package main

import (
"fmt"
"math/rand"
)

func main()
fmt.Println(rand.Float64())



From the docs:




Float64 returns, as a float64, a pseudo-random number in [0.0,1.0) from the default Source.







share|improve this answer























  • Precisely, no: golang.org/src/math/rand/rand.go?s=5359:5391#L168 doesn't return all possible values.

    – Ted
    Nov 13 '18 at 9:06











  • From the source comment: "Instead of that, if we round up to 1, just try again. Getting 1 only happens 1/2⁵³ of the time, so most clients will not observe it anyway.". They say they taken into account this.

    – Vincenzo Maggio
    Nov 13 '18 at 9:08












  • That's not the problem. The problem is that this code only returns multiples of 2⁻⁵³. Not all floating-point numbers between 0 and 1 are multiples of 2⁻⁵³, so you don't return all of them this way.

    – Ted
    Nov 13 '18 at 9:10











  • Listen, here's a discussion with even Russ Cox itself intervining: github.com/golang/go/issues/12290 saying this is not a huge problem. Thanks for the downvote.

    – Vincenzo Maggio
    Nov 13 '18 at 9:14











  • I added a comment explaining why I have a good reason not to use the code from the standard library. Thanks for making me notice that the rationale for my question was unclear! =)

    – Ted
    Nov 13 '18 at 9:20















-1














You can use rand Float64 function to return float in the [0, 1) range:



package main

import (
"fmt"
"math/rand"
)

func main()
fmt.Println(rand.Float64())



From the docs:




Float64 returns, as a float64, a pseudo-random number in [0.0,1.0) from the default Source.







share|improve this answer























  • Precisely, no: golang.org/src/math/rand/rand.go?s=5359:5391#L168 doesn't return all possible values.

    – Ted
    Nov 13 '18 at 9:06











  • From the source comment: "Instead of that, if we round up to 1, just try again. Getting 1 only happens 1/2⁵³ of the time, so most clients will not observe it anyway.". They say they taken into account this.

    – Vincenzo Maggio
    Nov 13 '18 at 9:08












  • That's not the problem. The problem is that this code only returns multiples of 2⁻⁵³. Not all floating-point numbers between 0 and 1 are multiples of 2⁻⁵³, so you don't return all of them this way.

    – Ted
    Nov 13 '18 at 9:10











  • Listen, here's a discussion with even Russ Cox itself intervining: github.com/golang/go/issues/12290 saying this is not a huge problem. Thanks for the downvote.

    – Vincenzo Maggio
    Nov 13 '18 at 9:14











  • I added a comment explaining why I have a good reason not to use the code from the standard library. Thanks for making me notice that the rationale for my question was unclear! =)

    – Ted
    Nov 13 '18 at 9:20













-1












-1








-1







You can use rand Float64 function to return float in the [0, 1) range:



package main

import (
"fmt"
"math/rand"
)

func main()
fmt.Println(rand.Float64())



From the docs:




Float64 returns, as a float64, a pseudo-random number in [0.0,1.0) from the default Source.







share|improve this answer













You can use rand Float64 function to return float in the [0, 1) range:



package main

import (
"fmt"
"math/rand"
)

func main()
fmt.Println(rand.Float64())



From the docs:




Float64 returns, as a float64, a pseudo-random number in [0.0,1.0) from the default Source.








share|improve this answer












share|improve this answer



share|improve this answer










answered Nov 13 '18 at 9:02









Vincenzo MaggioVincenzo Maggio

3,1152040




3,1152040












  • Precisely, no: golang.org/src/math/rand/rand.go?s=5359:5391#L168 doesn't return all possible values.

    – Ted
    Nov 13 '18 at 9:06











  • From the source comment: "Instead of that, if we round up to 1, just try again. Getting 1 only happens 1/2⁵³ of the time, so most clients will not observe it anyway.". They say they taken into account this.

    – Vincenzo Maggio
    Nov 13 '18 at 9:08












  • That's not the problem. The problem is that this code only returns multiples of 2⁻⁵³. Not all floating-point numbers between 0 and 1 are multiples of 2⁻⁵³, so you don't return all of them this way.

    – Ted
    Nov 13 '18 at 9:10











  • Listen, here's a discussion with even Russ Cox itself intervining: github.com/golang/go/issues/12290 saying this is not a huge problem. Thanks for the downvote.

    – Vincenzo Maggio
    Nov 13 '18 at 9:14











  • I added a comment explaining why I have a good reason not to use the code from the standard library. Thanks for making me notice that the rationale for my question was unclear! =)

    – Ted
    Nov 13 '18 at 9:20

















  • Precisely, no: golang.org/src/math/rand/rand.go?s=5359:5391#L168 doesn't return all possible values.

    – Ted
    Nov 13 '18 at 9:06











  • From the source comment: "Instead of that, if we round up to 1, just try again. Getting 1 only happens 1/2⁵³ of the time, so most clients will not observe it anyway.". They say they taken into account this.

    – Vincenzo Maggio
    Nov 13 '18 at 9:08












  • That's not the problem. The problem is that this code only returns multiples of 2⁻⁵³. Not all floating-point numbers between 0 and 1 are multiples of 2⁻⁵³, so you don't return all of them this way.

    – Ted
    Nov 13 '18 at 9:10











  • Listen, here's a discussion with even Russ Cox itself intervining: github.com/golang/go/issues/12290 saying this is not a huge problem. Thanks for the downvote.

    – Vincenzo Maggio
    Nov 13 '18 at 9:14











  • I added a comment explaining why I have a good reason not to use the code from the standard library. Thanks for making me notice that the rationale for my question was unclear! =)

    – Ted
    Nov 13 '18 at 9:20
















Precisely, no: golang.org/src/math/rand/rand.go?s=5359:5391#L168 doesn't return all possible values.

– Ted
Nov 13 '18 at 9:06





Precisely, no: golang.org/src/math/rand/rand.go?s=5359:5391#L168 doesn't return all possible values.

– Ted
Nov 13 '18 at 9:06













From the source comment: "Instead of that, if we round up to 1, just try again. Getting 1 only happens 1/2⁵³ of the time, so most clients will not observe it anyway.". They say they taken into account this.

– Vincenzo Maggio
Nov 13 '18 at 9:08






From the source comment: "Instead of that, if we round up to 1, just try again. Getting 1 only happens 1/2⁵³ of the time, so most clients will not observe it anyway.". They say they taken into account this.

– Vincenzo Maggio
Nov 13 '18 at 9:08














That's not the problem. The problem is that this code only returns multiples of 2⁻⁵³. Not all floating-point numbers between 0 and 1 are multiples of 2⁻⁵³, so you don't return all of them this way.

– Ted
Nov 13 '18 at 9:10





That's not the problem. The problem is that this code only returns multiples of 2⁻⁵³. Not all floating-point numbers between 0 and 1 are multiples of 2⁻⁵³, so you don't return all of them this way.

– Ted
Nov 13 '18 at 9:10













Listen, here's a discussion with even Russ Cox itself intervining: github.com/golang/go/issues/12290 saying this is not a huge problem. Thanks for the downvote.

– Vincenzo Maggio
Nov 13 '18 at 9:14





Listen, here's a discussion with even Russ Cox itself intervining: github.com/golang/go/issues/12290 saying this is not a huge problem. Thanks for the downvote.

– Vincenzo Maggio
Nov 13 '18 at 9:14













I added a comment explaining why I have a good reason not to use the code from the standard library. Thanks for making me notice that the rationale for my question was unclear! =)

– Ted
Nov 13 '18 at 9:20





I added a comment explaining why I have a good reason not to use the code from the standard library. Thanks for making me notice that the rationale for my question was unclear! =)

– Ted
Nov 13 '18 at 9:20

















draft saved

draft discarded
















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid


  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53277105%2fgenerate-uniformly-random-float-which-can-return-all-possible-values%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Use pre created SQLite database for Android project in kotlin

Darth Vader #20

Ondo