2

The standard Java libraries provide nice Collector utils for reduction, such as summingInt(), summingLong(), and summingDouble(). It does not look like there is summingFloat(), though. Is there a suggested workaround? Or perhaps are floats discouraged for some reason?

Josh Grinberg
  • 523
  • 6
  • 14
  • 1
    No idea if it is a good practice or not, but you can just look at `Collectors.summing...` implementation and try to write something like that yourself. It should take 2 min. – Amongalen May 14 '20 at 14:40
  • 2
    `Or perhaps are floats discouraged for some reason?` the general advise is to stay away from them because `doubles` offer far more accucary and the extra memory required doesn't really make a difference. – cegredev May 14 '20 at 14:47
  • though i'm not sure , but i think the reason is it's more precise to use double. – Akash Jain May 14 '20 at 14:47

2 Answers2

2

are floats discouraged for some reason?

Yes, they are discouraged because of the very low precision they have, as low as 6 digits (they have "from 6 to 9 significant decimal digits precision", according to Wikipedia).

The extra storage needed is generally not an issue, while the lack of precision can be a huge issue, that may not present itself with small test cases, so it's safer to use double unless absolute necessary.


If the objects you're streaming have a method returning a float, and you want to sum the values from that method, use summingDouble(...) and "cast" the result back to float using the floatValue() method of Double.

float sum = list.stream()
        .collect(Collectors.summingDouble(o -> o.getFloat()))
        .floatValue();
Andreas
  • 154,647
  • 11
  • 152
  • 247
1

Is there a suggested workaround?

You could convert the float values to double as follows:

Stream.of(1F, 2F, 3F).mapToDouble(Float::doubleValue).sum();

Or use reduce to sum the float values (mind that this will return a Optional<Float> instead of the primitive type as the previous solution do):

Stream.of(1F, 2F, 3F).reduce(Float::sum);

Or perhaps are floats discouraged for some reason?

It looks like the reason for the existence of only 3 primitive stream types is:

To avoid a lot of unnecessary object creation and work we have three primitive stream types

This answer also shows a similar reason for this.

Baeldung adds the boxing overhead argument to the matter:

Primitive streams are limited mainly because of boxing overhead and because creating specialized streams for other primitives isn't' that useful in many cases.


EDIT

As Karol mentioned in the comments, to avoid floating point innacuracy, you may convert it to float after using sum() from DoubleStream, as the first solution do:

float result = (float) Stream.of(1F, 2F, 3F).mapToDouble(Float::doubleValue).sum();

The API reference for sum() explains how it is different from simply reducing like reduce(0, Double::sum):

The order of addition operations of this method is intentionally not defined to allow for implementation flexibility to improve the speed and accuracy of the computed result. In particular, this method may be implemented using compensated summation or other technique to reduce the error bound in the numerical sum compared to a simple summation of double values.

Matheus Canon
  • 115
  • 1
  • 9