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

Several Improvements to the random package #3135

Merged
merged 5 commits into from
Apr 29, 2019
Merged

Conversation

mfelsche
Copy link
Contributor

I packaged those changes in 1 PR but left them as separate commits. If any of the changes is controversial or should be split, i am happy to do so.

Example benchmark run on my machine:

Benchmark                                   mean            median   deviation  iterations
random/int                                  3 ns              3 ns      ±0.31%     3000000
random/int-unbiased                        25 ns             25 ns      ±0.45%     2000000
random/int-fp-mult                         17 ns             17 ns      ±0.72%     3000000
random/next/mt                             11 ns             11 ns      ±0.69%     3000000
random/next/xorshift128+                    3 ns              3 ns      ±0.47%     3000000
random/next/xoroshiro128+                   3 ns              3 ns      ±0.67%     3000000
random/next/xoroshiro128**                  3 ns              3 ns      ±0.17%     3000000
random/next/splitmix64                      4 ns              4 ns      ±0.73%     3000000

Legend: random/int is the new fixed-point inversion method. random/int-fp-mult is the old Random.int implementation.

Copy link
Contributor

@srenatus srenatus left a comment

Choose a reason for hiding this comment

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

LGTM. Just some questions inline. Haven't checked the algorithms. ⚠


fun apply(h: TestHelper) =>
let xoroshiro128 = XorOshiro128StarStar(5489)
h.assert_eq[U64](xoroshiro128.next(), 529225608228480)
Copy link
Contributor

Choose a reason for hiding this comment

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

Would it be possible (and would you consider it worth doing) to instead iterate over a list of U64 instead of repeating this line over and over?

Copy link
Contributor

Choose a reason for hiding this comment

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

Also, are these test vectors from the papers, or from some other implementation? I suppose adding a comment where the numbers come from could be useful in the future.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The numbers are from executions of the reference implementation in C. I added comments about each source.

I also initially wanted to use a list to iterate over, but i decided against it, as the effort would have been roughly the same and the current version has the advantage that the error message in case of failure will tell you at which position it failed, without counting lines while iterating through a list.

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks! You're right about that line no detail, what you've chosen is better! =)

DoNotOptimise[U64](x)
DoNotOptimise.observe()

class iso RandomBenchmark[T: Random ref] is MicroBenchmark
Copy link
Contributor

Choose a reason for hiding this comment

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

Nice! :)

@@ -10,6 +10,15 @@ class XorShift128Plus is Random
var _x: U64
var _y: U64

new from_64bit(x: U64 = 5489) =>
Copy link
Member

Choose a reason for hiding this comment

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

Maybe from_u64 would be more consistent with other APIs?

Same comment applies to other additions.

@SeanTAllen
Copy link
Member

@mfelsche should this be squashed? should it be merged? it's unclear to me. i'll leave it to for you to merge/squash as needed.

@mfelsche
Copy link
Contributor Author

Sorry, I was off for a little while. I am gonna add manual changelog entries and squash while providing a proper commit message.

instead of floating-point multiplication.
But only use it if the platform supports native 128 bit ops, as we need to multiply with U128, because we cannot (yet) usesmaller types when generating e.g. U32 with Random.int. Waiting for specialized generic functions here.

Also added some benchmarks to show the performance increase.

http://www.pcg-random.org/posts/bounded-rands.html states it is just as biased as fp-mult version and a quick local test, generating a histogram showed proper uniform distribution.

Also added 'int_unbiased
a slower but unbiased function for generating bounded random numbers.
xoroshiro128** is a new xoroshiro variant with less bias in the low bits than xoroshiro128**
but also with a small performance impact.

Also use new parameters for xoroshiro128+ as described in the NOTE here:
http://xoshiro.di.unimi.it/xoroshiro128plus.c

splitmix64 is a PRNG which only needs 64 bits of state and is primarily used
to seed xoroshiro and xorshift generators from 64 bits only using the new 'from_64bits' constructors on those.

splitmix64 should only be used when 64 bit of state is a hard requirement, otherwise use xoroshiro128+ or xoroshiro128**.
@mfelsche mfelsche merged commit 18a5c87 into master Apr 29, 2019
@mfelsche mfelsche deleted the random-int-range branch April 29, 2019 18:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants