It turns out that, apparently, at least on tip (what I linked to) the fastrand implementation itself is actually pretty good. You might want to re-run the test on tip. fastrandn will still be somewhat biased.
On Fri, Oct 27, 2017 at 11:05 PM, Axel Wagner <axel.wagner...@googlemail.com > wrote: > Neither. fastrand is not a perfect PRNG, as that doesn't exist (much less > in…fast) and the reduction is biased (necessarily, unless you are going to > resort to rejection sampling, which is slow). > > On Fri, Oct 27, 2017 at 11:00 PM, T L <tapir....@gmail.com> wrote: > >> >> >> On Friday, October 27, 2017 at 4:57:46 PM UTC-4, T L wrote: >>> >>> >>> >>> On Friday, October 27, 2017 at 4:51:15 PM UTC-4, Axel Wagner wrote: >>>> >>>> Yes. The random number generator employed (right above from what I >>>> linked to; the fastrand function), apparently, is unsurprisingly imperfect. >>>> >>> >>> Why not to maintain a global start index for each goroutine? >>> The value of the start index is the number of executed select blocks in >>> a goroutine. >>> So that we can change the fastrandn implementation to >>> "return uint32(uint64(fastrand() + current_g.numExecutedSelects) * >>> uint64(n) >> 32)" >>> >> >> Aha, which function is unfair, fastrand or fastrandn? >> If fastrandn is unfair, then the above trick doesn't work. >> >>> >>> >>>> >>>> On Fri, Oct 27, 2017 at 10:47 PM, T L <tapi...@gmail.com> wrote: >>>> >>>>> It is also not uniform for powers of two. >>>>> If there a 8 cases, the sixth one will only get a 80% chance of the >>>>> first one. >>>>> >>>>> On Friday, October 27, 2017 at 4:33:47 PM UTC-4, Axel Wagner wrote: >>>>>> >>>>>> The code suggests, that select is indeed not fair: >>>>>> https://github.com/golang/go/blob/a4d03a9bf7604b727abd0a1ebf >>>>>> b118ff6366ee50/src/runtime/stubs.go#L109 >>>>>> Which seems fine to me. A fair, uniform PRNG for ranges that are not >>>>>> powers of two gets a fair bit of overhead and no program should depend on >>>>>> uniformity of select for correctness anyway. >>>>>> >>>>>> On Fri, Oct 27, 2017 at 10:28 PM, T L <tapi...@gmail.com> wrote: >>>>>> >>>>>>> It looks the distribution of the RNG results depends on the number >>>>>>> of cases. >>>>>>> The third case only gets the lowest possibility of there are 6 cases, >>>>>>> >>>>>>> >>>>>>> On Friday, October 27, 2017 at 4:21:12 PM UTC-4, T L wrote: >>>>>>>> >>>>>>>> A better example to show the inhomogeneity of the selected >>>>>>>> possibilities of each case. >>>>>>>> >>>>>>>> package main >>>>>>>> >>>>>>>> import "fmt" >>>>>>>> >>>>>>>> func main() { >>>>>>>> foo := make(chan struct{}) >>>>>>>> close(foo) >>>>>>>> var a, b, c, d, e, f, g float64 >>>>>>>> fa := func(){a++} >>>>>>>> fb := func(){b++} >>>>>>>> fc := func(){c++} >>>>>>>> fd := func(){d++} >>>>>>>> fe := func(){e++} >>>>>>>> ff := func(){f++} >>>>>>>> fg := func(){g++} >>>>>>>> for i := 0; i < 1000000; i++ { >>>>>>>> select { >>>>>>>> case <-foo: fa() >>>>>>>> case <-foo: fb() >>>>>>>> case <-foo: fc() >>>>>>>> case <-foo: fd() >>>>>>>> case <-foo: fe() >>>>>>>> case <-foo: ff() >>>>>>>> case <-foo: fg() >>>>>>>> } >>>>>>>> } >>>>>>>> fmt.Println(a/a) >>>>>>>> fmt.Println(b/a) >>>>>>>> fmt.Println(c/a) >>>>>>>> fmt.Println(d/a) >>>>>>>> fmt.Println(e/a) >>>>>>>> fmt.Println(f/a) >>>>>>>> fmt.Println(g/a) >>>>>>>> } >>>>>>>> >>>>>>>> result: >>>>>>>> >>>>>>>> 1 >>>>>>>> 0.9999052991869258 >>>>>>>> 0.9015652691532394 >>>>>>>> 0.9691884140319548 >>>>>>>> 0.966320332264567 >>>>>>>> 0.9669020658305938 >>>>>>>> 0.9604624105415533 >>>>>>>> >>>>>>>> On Friday, October 27, 2017 at 4:08:39 PM UTC-4, T L wrote: >>>>>>>>> >>>>>>>>> The following program constantly prints a value larger than 1.02 >>>>>>>>> >>>>>>>>> package main >>>>>>>>> >>>>>>>>> import "fmt" >>>>>>>>> >>>>>>>>> func main() { >>>>>>>>> foo, bar := make(chan struct{}), make(chan struct{}) >>>>>>>>> close(foo) >>>>>>>>> close(bar) >>>>>>>>> x, y := 0.0, 0.0 >>>>>>>>> f := func(){x++} >>>>>>>>> g := func(){y++} >>>>>>>>> for i := 0; i < 1000000; i++ { >>>>>>>>> select { >>>>>>>>> case <-bar: g() >>>>>>>>> case <-foo: f() >>>>>>>>> case <-bar: g() >>>>>>>>> case <-foo: f() >>>>>>>>> case <-bar: g() >>>>>>>>> case <-foo: f() >>>>>>>>> } >>>>>>>>> } >>>>>>>>> fmt.Println(x/y) >>>>>>>>> } >>>>>>>>> >>>>>>>>> if the last two cases are removed, then it becomes quit fair. >>>>>>>>> >>>>>>>> -- >>>>>>> You received this message because you are subscribed to the Google >>>>>>> Groups "golang-nuts" group. >>>>>>> To unsubscribe from this group and stop receiving emails from it, >>>>>>> send an email to golang-nuts...@googlegroups.com. >>>>>>> For more options, visit https://groups.google.com/d/optout. >>>>>>> >>>>>> >>>>>> -- >>>>> You received this message because you are subscribed to the Google >>>>> Groups "golang-nuts" group. >>>>> To unsubscribe from this group and stop receiving emails from it, send >>>>> an email to golang-nuts...@googlegroups.com. >>>>> For more options, visit https://groups.google.com/d/optout. >>>>> >>>> >>>> -- >> You received this message because you are subscribed to the Google Groups >> "golang-nuts" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to golang-nuts+unsubscr...@googlegroups.com. >> For more options, visit https://groups.google.com/d/optout. >> > > -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.