Additional Blogs by Members
cancel
Showing results for 
Search instead for 
Did you mean: 

Latest news

Most of the issues described in this blog have been rectified as of SP18. See my blog New Arithmetic and Statistical Functions in Message Mappings in SP18 for details.


Introduction

The built-in arithmetic funtions in XI's Message Mappings include common functions like add, subtract, multiply, and divide as well as less common functions like sqrt, ceil, and floor and a variety of others.

The problem with these built-in functions is actually explicitly stated in the documentation: "all calculations are executed with the precision of the Java data type float". What is not stated, unfortunately, is the implication of this seemingly innocent statement.

Implication of using float

The best way to illustrate the problem is with a simple example. Say you want to divide a given number by 100, for instance in order to move the decimal point. Easily done with the following field mapping, right?

If you execute this with an input value of 85328698, the unexpected result is 853286.94. Notice that this is not even the result you would expect if the number was simply being rounded off. And I'll bet this is not an acceptable discrepancy for your accounting department!

I won't get into the technical details here, but there is an excellent article at IBM DeveloperWorks explaining some of the intricacies of floating point numbers in Java.

By now you should be convinced that floats should not be used when precision matters. But when does precision matter? Definitely whenever monetary amounts are used. But I would argue that no numbers should ever lose precision in a mapping, unless this is explicitly requested.

What to do instead

Well, don't fall into the trap of writing a User-Defined Function and just using double instead of float. This may offset the problem a little, but the double data type suffers from exactly the same problems as float.

Instead, Java provides two classes for dealing with arbitrary precision integer and decimal values in the java.math package: BigDecimal and BigInteger. These classes provide methods equivalent to many of the built-in arithmetic functions, albeit they do require you to specify exactly how you want rounding to be performed every time you perform an operation that can result in a loss of precision.

Here's the division-by-100 example implemented using BigDecimal:

...which yields the expected result: 853286.98. Notice it doesn't actually divide by 100, but simply moves the decimal point.

Here are a few more functions to get you going with BigDecimals:

add

String add(String a, String b) { BigDecimal bigA = new BigDecimal(a); BigDecimal bigB = new BigDecimal(b); BigDecimal bigSum = bigA.add(bigB); return bigSum.toString(); }

round

String round(String num) { BigDecimal original = new BigDecimal(num); BigDecimal rounded = original.setScale(0, BigDecimal.ROUND_HALF_UP); return rounded.toString(); }
Summary

When I say "never, ever use XI's built-in arithmetic functions", I mean it. The only case where their use may be justified is for statistical values where you are absolutely certain that precision is not important. But why would you be calculating that sort of thing in an XI mapping program?

7 Comments