Skip to Content

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?

image

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:

image

…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?

To report this post you need to login first.

7 Comments

You must be Logged on to comment or reply to a post.

  1. Anonymous
    The buildt-in functions SUM and NEG are also inaccurate with values approximately over 260000!

    Any SP’s that fixes this?

    (0) 
    1. Thorsten Nordholm Søbirk Post author
      Thanks for pointing this out, Rune. I had overlooked these functions. They also use the float data type internally and therefore suffer from the same problems.

      I think the only way for SAP to fix this would be to introduce a second set of arithmetic and statistical functions base on BigDecimal. Because the existing functions are part of a public API, SAP risks breaking existing mappings if they change them, even though those same mappings are actually already broken 😉

      Best regards,
      Thorsten

      (0) 
    1. Thorsten Nordholm Søbirk Post author
      Hi Michal,

      Thanks! I have indeed seen this. I hope to update the blog (and maybe write a new one on the new functionality) shortly, i.e. as soon as I get the time 🙂

      Regards,
      Thorsten

      (0) 
  2. Robert Burfoot-Lobo
    Note 958486 introduces a new setting (com.sap.aii.mappingtool.flib3.bigdecimalarithmetic) that make most of PI’s built-in arithmetic and statistical functions use BigDecimal instead of float, which resolves the issue.

    We were going to apply this setting in our environment, but first I wanted to make a mapping that shows the problem, so I can confirm that the setting change fixes it.

    I cannot reproduce the float issue in a graphical mapping with the example given in this blog, nor with classic examples of 2.11 + 22.11, nor with 0.1 added to itself 20 times.

    We are on PI 7.1 SPK 7. Does 7.1 always use BigDecimal perhaps?

    RBL

    (0) 
    1. Thorsten Nordholm Søbirk Post author
      PI 7.1 might use BigDecimal by default but I have been unable to confirm this.
      The documentation for the standard functions in 7.1 (http://help.sap.com/saphelp_nwpi711/helpdata/en/43/c4cdfc334824478090739c04c4a249/frameset.htm) contains the wording “If the particular usage case requires more detailed results, you can also select the decimal system as the basis for the calculations. The Java class BigDecimal is used for internal purposes. For more details see SAP Note 958486.” which unfortunately sheds no futher light on the situation because the note doesn’t mention PI 7.1.
      Perhaps someone from SAP would care to clarify this?

      – Thorsten

      (0) 

Leave a Reply