HiveBrain v1.2.0
Get Started
← Back to all entries
snippetjavaMinor

Numerical streams example

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
numericalexamplestreams

Problem

I am reading "Java 8 In Action" (by Raoul-Gabriel Urma, Mario Fusco and Alan Mycroft), section 5.6.3, pages 116 and 117. The code that is presented handles calculating so-called "Pythagorean Triples". Page 116 shows the first attempt, and page 117 shows an improved attempt to generate these triples, where both use the .rangeClosed() method.

I have found some optimizations that go beyond the book and I would like to share them here. I did some simple System.currentTimeMillis() calculations to see if my modifications were improvements, and they appeared to be marginally better than that found in the book. Can you provide better improvements, explanations or metrics for this code?

```
public void test() {

long time1 = System.currentTimeMillis();

/*
* From text, page 116
*/
IntStream.rangeClosed(1, 100).boxed()
.flatMap(a -> IntStream.rangeClosed(a, 100)
.filter(b -> Math.sqrt(aa + bb) % 1 == 0)
.mapToObj(b -> new int[]{a, b, (int)Math.sqrt(aa + bb)})
)
.forEach(c -> System.out.println("["+c[0]+" "+c[1]+" "+c[2]+"]"));

long time2 = System.currentTimeMillis();

System.out.println();

long time3 = System.currentTimeMillis();

/*
* From text, page 117, I added "map(...)" so that end result are ints, not doubles
*/
IntStream.rangeClosed(1, 100).boxed()
.flatMap(a -> IntStream.rangeClosed(a, 100)
.mapToObj(b -> new double[]{a, b, Math.sqrt(aa + bb)})
.filter(t -> t[2] % 1 == 0)
.map(b -> new int[]{(int)b[0], (int)b[1], (int)b[2]})
)
.forEach(c -> System.out.println("["+c[0]+" "+c[1]+" "+c[2]+"]"));

long time4 = System.currentTimeMillis();

System.out.println();

long time5 = System.currentTimeMillis();

/*
* My optimization attempt #1: now mapToObj(...) has c%1!=0 conditional, filter checks array element not null
*/
IntStream.rangeClosed(1, 100).boxed(

Solution

What the original code does is, that it calculates the (relatively expensive) Math.sqrt(a a + b b) twice: once for filtering, the second time for generating the end result.

You eliminated this double calculation by caching the results, thus your code is a wee bit faster.

Note however, that the benchmark you did is probably not valid, I suggest reading the accepted answer in https://stackoverflow.com/questions/504103/how-do-i-write-a-correct-micro-benchmark-in-java as a starter.

Then, be aware that this micro-optimization only pays if you get into serious number crunching. As D.E.Knuth exclaimed (and it still holds true): "premature optimization is the root of all evil" (http://wiki.c2.com/?PrematureOptimization) so think twice before you optimize on that level.

Furthermore, if you are really serious about "the best" production code, this shuffeling around with two arrays seems akward: if you want a structure which holds two ints and a double, then create a structure with two ints and a double, give it a good name, and use that instead of arrays. This will eliminate the cast-int-to-double-and-back-to-int that you do and make the concept a bit clearer to the reader.

Context

StackExchange Code Review Q#152086, answer score: 3

Revisions (0)

No revisions yet.