[英]How to efficiently generate only odd (or even) random numbers?
From looking at other questions regarding the generation of only even or odd numbers, I was curious as to what method would be the most efficient (in terms of speed). 通过查看关于仅生成奇数或偶数的其他问题,我很好奇哪种方法(在速度方面)最有效。
For example, let's say that I wanted to generate many odd numbers that range from 1 (inclusive) to 1000 (exclusive); 例如,假设我想生成许多奇数,范围从1(含)到1000(不含); for each iteration, the method I would normally use is the following:
对于每次迭代,我通常使用的方法如下:
2
2
1
1
Is there any better method? 有没有更好的方法?
I happened to stumble upon this method today and I can't find any use of it on StackOverflow for generating only even or odd numbers. 我今天偶然发现了这种方法,并且在StackOverflow上找不到用于生成偶数或奇数的任何用法。
This method takes advantage of the fact that, in binary, all even numbers (including 0
) have their least-significant bit set to 0
whereas all odd numbers have their least-significant bit set to 1
. 该方法利用以下事实:二进制的所有偶数(包括
0
)的最低有效位均设置为0
而所有奇数的最低有效位均设置为1
。
Therefore, to generate an odd number, we can simply generate a random number within the desired range and bitwise-or it with 1
: 因此,要生成一个奇数,我们可以简单地生成一个期望范围内的随机数,然后按位或
1
生成一个随机数:
ThreadLocalRandom.current().nextInt(0, 1_000) | 1
With this method, if the generator selects an odd number, then it is left alone. 使用这种方法,如果生成器选择了一个奇数,则将其保留下来。 However, if an even number is selected, then bitwise-or'ing it with
1
essentially increments it. 但是,如果选择了偶数,则将其按
1
进行按位或运算实质上会使其递增。
Likewise, to generate even numbers between 2
(inclusive) and 1000
(exclusive), then we just need to clear the least-significant bit. 同样,要生成介于
2
(含)和1000
(不含)之间的偶数,则只需要清除最低有效位即可。 To do this, we can simply bitwise-and the value with -2
: 为此,我们可以简单地按位运算-然后用
-2
表示值:
ThreadLocalRandom.current().nextInt(2, 1_000) & -2
With this method, if the generator selects an even number, then it is left alone. 使用这种方法,如果生成器选择一个偶数,则它会被保留。 However, if an odd number is selected, then bitwise-and'ing it with
-2
essentially decrements it. 但是,如果选择了奇数,则按位加“
-2
实际上会使它递减。
These methods work perfectly fine with negative values, and long
as well. 这些方法的工作负值完美的罚款,并
long
为好。
Here is a JMH benchmark comparing the two methods for generating an odd number between 1
(inclusive) and 1000
(exclusive): 这是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;
}
}
And the results: 结果:
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
can be improved slightly by using << 1
instead of * 2
, but newMethod
is still slightly faster. oldMethod
可以稍微通过使用能够提高<< 1
代替* 2
,但newMethod
仍然是稍快。
Your 2n + 1
approach is good. 您的
2n + 1
方法很好。 You can use streams and wrap it up in a helper method for ease of use if you like: 如果愿意,您可以使用流并将其包装在帮助程序方法中,以便于使用:
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);
}
Usage: 用法:
randomOdds(1, 1000).limit(20).forEach(System.out::println);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.