MathFlux sumBigDecimal looses scale of BigDecimal
kiwisincebirth opened this issue · comments
MathFlux sumBigDecimal looses scale of BigDecimal. And is not respecting standard BigDecimal behaviour.
Expected Behavior
The summation in the Flux should follow BigDecimal arithmetic, using a standard plus() operator provided by BigDecimal.
Actual Behavior
The summation logic is loosing precision, and the cause is related to the conversion of BigDecimal to it Double value
Steps to Reproduce
The following test case (Kotlin code) highlights the error. I have not tried this in Java, but assume the same issue would be prevalent in Java Code also.
@Test
fun test() {
val ONE = BigDecimal("1.00")
val ONE_PLUS_ONE = ONE.plus(ONE)
val sumBigDecimal = MathFlux.sumBigDecimal(Flux.just(ONE,ONE)).block()
assertThat(sumBigDecimal).isEqualTo(ONE_PLUS_ONE)
}
the result if the above is
expected: 2.00
but was : 2.0
org.opentest4j.AssertionFailedError:
Possible Solution
The issue seems to be in the Class MonoSumBigDecimal Line:77
BigDecimal bigDecimalValue = BigDecimal.valueOf(number.doubleValue());
where the Number being processed in the stream, is converted via Double back to a BigDecimal. For the general case of Number this is fine. but in this case the Number (IS) a bigdecimal and does not need to be cast in this way.
BigDecimal bigDecimalValue = (number instanceof BigDecimal) ?
(BigDecimal) number : new BigDecimal(number.toString());
noting that number.toString() is my (OPINION) of how to convert a Number more generally into a BigDecimal, since the translation avoids the Double type.
I am fairly sure MonoAverageBigDecimal suffers from the same issue, since it has the same line of code indicated above.
Your Environment
Not Relevant the above test case fairly easy to reproduce
- Reactor version(s) used: 3.4.3
- JVM version (
java -version
): 11
That's a great catch @kiwisincebirth!
After having looked into your suggestion to use the BigDecimal(String value)
constructor, I agree this seems like the best approach 👍
Would you like to submit a fixing PR for both sum and average?
See The pull Request #261 for the change I proposed.
I have updated all but one test to use verifyResult() instead of verifyBigDecimalResult() - It turns out the verifyBigDecimalResult() was actually masking the precision issue! Because verifyBigDecimalResult() uses compareTo() ==0 for its comparisons. Simply changing Tests to use verifyResult() - highlighted the stated issue.