Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sorting (a stream of) doubles by absolute magnitude

I have a series of double values which I want to sum up and get the maximum value. The DoubleStream.summaryStatistics() sounds perfect for that. The getSum() method has an API note reminding me of what I learned during one of my computer science courses: the stability of the summation problem tends to be better if the values are sorted by their absolute values. However, DoubleStream does not let me specify the comparator to use, it will just use Double.compareTo if I call sorted() on the stream.

Thus I gathered the values into a final Stream.Builder<Double> values = Stream.builder(); and call

values.build()
    .sorted(Comparator.comparingDouble(Math::abs))
    .mapToDouble(a -> a).summaryStatistics();

Yet, this looks somewhat lengthy and I would have preferred to use the DoubleStream.Builder instead of the generic builder. Did I miss something or do I really have to use the boxed version of the stream just to be able to specify the comparator?

like image 815
muued Avatar asked May 18 '15 09:05

muued


People also ask

Which method is used to sort the Stream?

Java Stream sorted() Learn to use Stream sorted() method to sort the elements in a Stream by their natural order.

How do you sort an array by absolute value?

Given an array of integers arr , write a function absSort(arr) , that sorts the array according to the absolute values of the numbers in arr . If two numbers have the same absolute value, sort them according to sign, where the negative numbers come before the positive numbers. Constraints: [time limit] 5000ms.

How do I sort a list in streams?

Sorting a List of Integers with Stream. Found within the Stream interface, the sorted() method has two overloaded variations that we'll be looking into. This methods returns a stream consisting of the elements of the stream, sorted according to natural order - the ordering provided by the JVM.

How do you sort a double in Java?

The java. util. Arrays. sort(double[]) method sorts the specified array of doubles into ascending numerical order.


2 Answers

Primitive streams don't have an overloaded sorted method and will get sorted in natural order. But to go back to your underlying problem, there are ways to improve the accuracy of the sum that don't involve sorting the data first.

One such algorithm is the Kahan summation algorithm which happens to be used by the OpenJDK/Oracle JDK internally.

This is admittedly an implementation detail so the usual caveats apply (non-OpenJDK/Oracle JDKs or future OpenJDK JDKs may take alternative approaches etc.)

See also this post: In which order should floats be added to get the most precise result?

like image 133
assylias Avatar answered Oct 10 '22 17:10

assylias


The only possible way to sort DoubleStream is to box/unbox it:

double[] input = //...
DoubleStream.of(input).boxed()
    .sorted(Comparator.comparingDouble(Math::abs))
    .mapToDouble(a -> a).summaryStatistics();

However as Kahan summation is used internally, the difference should be not very significant. In most of applications unsorted input will yield the good resulting accuracy. Of course you should test by yourself if the unsorted summation is satisfactory for your particular task.

like image 11
Tagir Valeev Avatar answered Oct 10 '22 15:10

Tagir Valeev