繁体   English   中英

如何有效地仅生成奇数(或偶数)随机数?

[英]How to efficiently generate only odd (or even) random numbers?

通过查看关于生成奇数或偶数的其他问题,我很好奇哪种方法(在速度方面)最有效。

例如,假设我想生成许多奇数,范围从1(含)到1000(不含); 对于每次迭代,我通常使用的方法如下:

  • 生成介于0(含)和500(不含)之间的随机数
  • 乘以2
  • 1

有没有更好的方法?

我今天偶然发现了这种方法,并且在StackOverflow上找不到用于生成偶数或奇数的任何用法。

该方法利用以下事实:二进制的所有偶数(包括0 )的最低有效位均设置为0而所有奇数的最低有效位均设置为1

因此,要生成一个奇数,我们可以简单地生成一个期望范围内的随机数,然后按位或1生成一个随机数:

ThreadLocalRandom.current().nextInt(0, 1_000) | 1

使用这种方法,如果生成器选择了一个奇数,则将其保留下来。 但是,如果选择了偶数,则将其按1进行按位或运算实质上会使其递增。

同样,要生成介于2 (含)和1000 (不含)之间的偶数,则只需要清除最低有效位即可。 为此,我们可以简单地按位运算-然后用-2表示值:

ThreadLocalRandom.current().nextInt(2, 1_000) & -2

使用这种方法,如果生成器选择一个偶数,则它会被保留。 但是,如果选择了奇数,则按位加“ -2实际上会使它递减。

这些方法的工作负值完美的罚款,并long为好。

这是JMH基准测试,比较了生成1 (含)和1000 (不含)之间的奇数的两种方法:

@State(Scope.Benchmark)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Warmup(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS)
@Measurement(iterations = 20, time = 500, timeUnit = TimeUnit.MILLISECONDS)
@Fork(5)
public class MyBenchmark {

    private static final ThreadLocalRandom RANDOM = ThreadLocalRandom.current();

    public static void main(String[] args) throws Exception {
        org.openjdk.jmh.Main.main(args);
    }

    @Benchmark
    public int oldMethod() {
        return RANDOM.nextInt(0, 500) * 2 + 1;
    }

    @Benchmark
    public int newMethod() {
        return RANDOM.nextInt(0, 1000) | 1;
    }
}

结果:

Benchmark              Mode  Cnt  Score   Error  Units
MyBenchmark.newMethod  avgt  100  6.079 ± 0.137  ns/op
MyBenchmark.oldMethod  avgt  100  6.325 ± 0.009  ns/op

oldMethod可以稍微通过使用能够提高<< 1代替* 2 ,但newMethod仍然是稍快。

您的2n + 1方法很好。 如果愿意,您可以使用流并将其包装在帮助程序方法中,以便于使用:

import java.util.Random;

public static IntStream randomOdds(int from, int upTo) {
    return new Random().ints(from/2, upTo/2).map(n -> 2*n + 1);
}

用法:

randomOdds(1, 1000).limit(20).forEach(System.out::println);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM