I have this algorithm right here,
while ((start + end) / 2 != 0) { Double mid = (start + end) / 2; if (Math2.pow(mid, 3) < n) { start = mid; } else if (Math.abs(n - Math2.pow(mid, 3)) > Math2.pow(e, 3)) { end = mid; } else if (Math.abs(n - Math2.pow(mid, 3)) < Math2.pow(e, 3)) { return mid; } } return 0.0; }
that gives me the cubic root of n with a loss precision of e. I need to do the same thing but using Java 8 Streams. Math2 is from a private git rep. You can use Math.pow instead; it will work too. How can I do the same algorithm with Streams?
Advertisement
Answer
Java Stream API has method Stream::iterate
starting from Java 9, therefore a class representing the iteration steps/states may be implemented as follows:
class CubeSolver { static final double EPS = 1E-06; private double start, end, n, mid; public CubeSolver(double s, double e, double n) { this.start = s; this.end = e; this.n = n; this.mid = (start + end) / 2; } // UnaryOperator<CubeSolver> for iteration public CubeSolver next() { if (done()) { return this; } if (Math.pow(mid, 3) < n) { start = mid; } else if (Math.abs(n - Math.pow(mid, 3)) > EPS) { end = mid; } return new CubeSolver(start, end, n); } // define end of calculation public boolean done() { return mid == 0 || Math.abs(n - Math.pow(mid, 3)) < EPS; } @Override public String toString() { return "root = " + mid; } }
Then the stream-based solution looks like this:
- define an initial seed with
start
,end
,n
- use
Stream::iterate
withhasNext
predicate to create a finite stream 2a) or use olderStream::iterate
withouthasNext
but withStream::takeWhile
operation to conditionally limit the stream – also available since Java 9 - use
Stream::reduce
to get the last element of the stream
CubeSolver seed = new CubeSolver(1.8, 2.8, 8); CubeSolver solution = Stream .iterate(seed, cs -> !cs.done(), CubeSolver::next) .reduce((first, last) -> last) // Optional<CubeSolver> .orElse(null); System.out.println(solution);
Output:
root = 2.0000002861022947
In Java 11 static Predicate::not
was added, so the 2a solution using takeWhile
could look like this:
CubeSolver seed = new CubeSolver(0, 7, 125); CubeSolver solution = Stream .iterate(seed, CubeSolver::next) .takeWhile(Predicate.not(CubeSolver::done)) .reduce((first, last) -> last) // Optional<CubeSolver> .orElse(null); System.out.println(solution);
Output (for EPS = 1E-12):
root = 4.999999999999957