roundNumber built in service not working as expected

Hi All,

I am trying to round a number in the format whole_part.decimal_part. Say, irrrespective of the length of the number, i want to round that number upto 2 places of decimal.
I am using the built-in service pub.math:roundNumber with inputs as -

num (the input number),
numberOfDigits (2)
roundingMode(roundHalfUp)

So far, it has given me the below outputs-

12345678979784.56898 =>12345678979784.57
123456789797845.56898 =>123456789797845.56
797845.56898 =>797845.57

My question is:

  1. Why for the second case, it has not rounded the decimals? Is there any limitations as to till how many digits can the whole_part be, for it to round the decimals?
  2. Is the built-in service capable of rounding digits of any length?

Please advise.

It appears that it may be constrained somehow. Perhaps by enforcing limits of double in some way. I’d open a ticket with support to get an explanation of the behavior.

2 Likes

Same is the case with pub.math:addFloats.

Hi Atul,
This does seem like a bug to me. And may be related to BigDecimal support. Please raise a ticket and we should be able to work on this.
Thanks,
Sree

1 Like

I suspect that it is related to the implementation using float/double in some way. For addFloats, it is definitely the root cause. In the past I encountered this where BigDecimal was being used – but float/double was used before the BigDecimal object was created. Which completely defeats the purpose of using BigDecimal to avoid float/double accuracy/precision characteristics.

People are often surprised about how float/double can behave. The JVM takes steps to account for the behaviors and tries to best match “expected” behavior but cannot always do so. It has improved over the years but still has gotchas – which are very hard to identify when they occur. I’ll leave the details about the behaviors as a search activity for the reader – there is a good amount of material on the web about float/double and how they must be avoided when dealing with values that represent data such as currency where accuracy is crucial. The item that helps one to remember to avoid float: 0.1 in decimal is a repeating fraction in binary, and is an illustration of the accuracy concerns with float/double.

We long ago adopted a practice of never using the pub.math services for decimal calculations and instead have Java services that lightly wrap the BigDecimal methods. And these never, ever use float/double constructs in any way.

Try this: call pub.math.multiplyFloats with 3 and 13.20

Depending upon IS fixes and some other aspects, chances are the result is 39.599999999999994 instead of 39.6.

This is because float/double are inaccurate. Useful in many contexts but for general business applications, it is not. This is not specific to Java. Or any OS. Or any specific runtime. It is the nature of binary arithmetic.

I’ve seen applications the are littered with using float/double and round and trunc operations in attempts to “fix the JVM bug”. They are not bugs.

Avoid float/double unless you know you need it for non-monetary purposes. I fully suspect roundNumber is a victim of this too. Write your own BigDecimal services to use instead. Doing so is easy. We named ours addDecimals, multiplyDecimals, etc. and have the signatures match the same inputs and outputs as the WmPublic services. Here is an example of one of them:

	public static final void addDecimals(IData pipeline) throws ServiceException {
		IDataCursor idc = pipeline.getCursor();
		String num1 = IDataUtil.getString(idc, "num1");
		String num2 = IDataUtil.getString(idc, "num2");
		
		// Note that these constructors may throw NPE if
		// num1 and/or num2 are not passed to the service.
		// This mimics pub.math:addFloats.
		java.math.BigDecimal n1 = new java.math.BigDecimal(num1);
		java.math.BigDecimal n2 = new java.math.BigDecimal(num2);
		
		IDataUtil.put(idc, "value", n1.add(n2).toString());
		idc.destroy();
	}

BigDecimal isn’t the culprit in this case. It is the underlying use of double by the pub.math implementations.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.