I am observing some peculiar behavior with Java8
and the new Stream-API
.
I would expect the performance of the following two statements to be identical, but it's not.
LongStream.iterate(1, n -> n + 1).limit(5000)
.anyMatch(n -> isPerfectCube((n*n*n)+((n*n)*p)));
versus
LongStream.iterate(1, n -> n + 1)
.anyMatch(n -> isPerfectCube((n*n*n)+((n*n)*p)));
Both statements should return true
, and I wouldn't expect any performance difference given that they can both short circuit on the first match found. The only difference in the statements is that one is bounded in an upper limit on the range of numbers to iterate, while the other is not.
Can someone explain to me why one would run faster and use less memory than the other?
There are some values of p
where the condition is true for large values of n
. For example with p = 3
, the condition becomes true for n = 50_331_648
. In that case, the limit of 5000 will of course win in terms of performance but the two calculations won't return the same result.
I have randomly picked a p
(3002) that returns true for n
less than 5000 and the results are very close (although the version with limit
is slightly slower, probably because of the extra condition n < 5000
).
Benchmark results (in micro-seconds per call to anyMatch
):
Benchmark Mode Samples Mean Mean error Units
c.a.p.SO24003674.limit avgt 5 130.165 2.663 us/op
c.a.p.SO24003674.noLimit avgt 5 126.876 2.440 us/op
Benchmark code (using jmh):
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@State(Scope.Thread)
@Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)
@Measurement(iterations = 5, time = 1000, timeUnit = TimeUnit.MILLISECONDS)
@Fork(1)
public class SO24003674 {
private int p = 3002;
@GenerateMicroBenchmark
public boolean limit() {
return LongStream.iterate(1, n -> n + 1).limit(5000)
.anyMatch(n -> isPerfectCube((n * n * n) + ((n * n) * p)));
}
@GenerateMicroBenchmark
public boolean noLimit() {
return LongStream.iterate(1, n -> n + 1)
.anyMatch(n -> isPerfectCube((n * n * n) + ((n * n) * p)));
}
private static boolean isPerfectCube(long n) {
long tst = (long) (Math.cbrt(n) + 0.5);
return tst * tst * tst == n;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With