通过查看有关生成仅偶数或奇数的其他问题,我很好奇哪种方法最有效(就速度而言)。
例如,让我们说我想生成许多奇数,范围从1(含)到1000(不包括);对于每次迭代,我通常使用的方法如下:
2
1
有没有更好的方法?
答案 0 :(得分:4)
我今天碰巧偶然发现了这种方法,我无法在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
仍然稍快一些。
答案 1 :(得分:1)
您的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);