我在这里写了这两个方法来找到最小值和最大值。#2是基于这个帖子这个答案在这里。
private static Pair classicMinMax(int[] elements) {
int min = MAX_VALUE;
int max = MIN_VALUE;
for (int i = 0; i < elements.length; i++) {
int e = elements[i];
if (e < min) min = e;
if (e > max) max = e;
}
return new Pair(min, max);
}
private static Pair divideAndConquer(int[] elements) {
int min = MAX_VALUE;
int max = MIN_VALUE;
for (int i = 0; i < elements.length - 1; i += 2) {
int a = elements[i];
int b = elements[i + 1];
if (a > b) {
if (b < min) min = b;
if (a > max) max = a;
} else {
if (a < min) min = a;
if (b > max) max = b;
}
}
if (elements.length % 2 != 0) {
int lastElement = elements[elements.length - 1];
if (lastElement < min) min = lastElement;
if (lastElement > max) max = lastElement;
}
return new Pair(min, max);
}
如果我运行这样的简单基准测试:
@Test
public void timingsBoth() throws Exception {
int size = 1000;
for (int i = 1000; i < 10_000; i += 1000) {
int arraySize = size * i;
System.out.println("step is " + arraySize);
List<Integer> list = new ArrayList<>(arraySize);
int[] elements = new int[arraySize];
for (int k = 0; k < arraySize; k++) {
list.add(k);
}
Collections.shuffle(list);
Integer[] integers = list.toArray(new Integer[0]);
for (int k = 0; k < arraySize; k++) {
elements[k] = integers[k];
}
long start = currentTimeMillis();
classicMinMax(elements);
long stop = currentTimeMillis();
long result = stop - start;
System.out.println("classic is " + result);
start = currentTimeMillis();
divideAndConquer(elements);
stop = currentTimeMillis();
result = stop - start;
System.out.println("divideAndConquer is " + result);
}
}
}
我通常会得到这个结果:
step is 1000000 classic is 8 divideAndConquer is 11 step is 2000000 classic is 2 divideAndConquer is 5 step is 3000000 classic is 11 divideAndConquer is 17 step is 4000000 classic is 5 divideAndConquer is 10 step is 5000000 classic is 4 divideAndConquer is 16 step is 6000000 classic is 6 divideAndConquer is 14 step is 7000000 classic is 6 divideAndConquer is 18 step is 8000000 classic is 8 divideAndConquer is 20 step is 9000000 classic is 8 divideAndConquer is 24
我弄错了算法吗?我期待至少有类似的结果。
好的,根据评论中的建议,我认为我做了一个更好的基准测试。我使用的是Java Microbenchmark Harness。我以前从未使用过它,所以我的测试基于这个方便的教程。
我所做的是创建一个 JMH 测试,如下所示:
public class MinMaxBenchmark {
@State(Scope.Benchmark)
public static class MyState {
int arraySize = 50_0000;
int[] elements = new int[arraySize];
@Setup(Level.Trial)
public void doSetup() {
List<Integer> list = new ArrayList<>(arraySize);
for (int k = 0; k < arraySize; k++) {
list.add(k);
}
Collections.sort(list);
Integer[] integers = list.toArray(new Integer[0]);
for (int k = 0; k < arraySize; k++) {
elements[k] = integers[k];
}
}
}
@Benchmark @BenchmarkMode(Mode.SampleTime ) @OutputTimeUnit(TimeUnit.MILLISECONDS)
public Pair classic(MyState state) {
return classicMinMax(state.elements);
}
@Benchmark @BenchmarkMode(Mode.SampleTime) @OutputTimeUnit(TimeUnit.MILLISECONDS)
public Pair divide(MyState state) {
return divideAndConquer(state.elements);
}
}
我特别注意在@State
使用@Setup
初始化方法的基准测试之外创建数组(输入数据)。比我写的@Benchmark
方法。我在返回结果时非常小心,因此可以避免死代码(全部在教程中)。
通过这种设置,我进行了多次试验。这是最后一次尝试:
Benchmark Mode Cnt Score Error Units MinMaxBenchmark.classic sample 994028 0.202 ± 0.001 ms/op MinMaxBenchmark.classic:classic·p0.00 sample 0.153 ms/op MinMaxBenchmark.classic:classic·p0.50 sample 0.180 ms/op MinMaxBenchmark.classic:classic·p0.90 sample 0.259 ms/op MinMaxBenchmark.classic:classic·p0.95 sample 0.311 ms/op MinMaxBenchmark.classic:classic·p0.99 sample 0.409 ms/op MinMaxBenchmark.classic:classic·p0.999 sample 0.567 ms/op MinMaxBenchmark.classic:classic·p0.9999 sample 0.942 ms/op MinMaxBenchmark.classic:classic·p1.00 sample 2.617 ms/op MinMaxBenchmark.divide sample 1226029 0.164 ± 0.001 ms/op MinMaxBenchmark.divide:divide·p0.00 sample 0.126 ms/op MinMaxBenchmark.divide:divide·p0.50 sample 0.149 ms/op MinMaxBenchmark.divide:divide·p0.90 sample 0.201 ms/op MinMaxBenchmark.divide:divide·p0.95 sample 0.230 ms/op MinMaxBenchmark.divide:divide·p0.99 sample 0.327 ms/op MinMaxBenchmark.divide:divide·p0.999 sample 0.522 ms/op MinMaxBenchmark.divide:divide·p0.9999 sample 0.945 ms/op MinMaxBenchmark.divide:divide·p1.00 sample 3.199 ms/op
实际上,鸿沟仅在p1.00 上失败(我需要找到含义)。
所以我想这是我处理基准测试的方式的问题。
感谢您在评论中的帮助,尤其是@alfasin。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句