The issue is that the PSUtilities.math services should not be used when accuracy is required. They use float/double types which have accuracy issues. There are a few threads on the forums that speak to this. Do a search for BigDecimal to find them.
You probably want to write a set of services that use BigDecimal to do add, subtract, multiply, divide and round. Here’s some source you can use if desired (no warranties/support):
[highlight=java]
// add service - Adds two numbers using java.math.BigDecimal.
IDataCursor idc = pipeline.getCursor();
String num1 = IDataUtil.getString(idc, “num1”);
String num2 = IDataUtil.getString(idc, “num2”);
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();
// subtract service - Subtracts num2 from num1 using java.math.BigDecimal.
IDataCursor idc = pipeline.getCursor();
String num1 = IDataUtil.getString(idc, “num1”);
String num2 = IDataUtil.getString(idc, “num2”);
java.math.BigDecimal n1 = new java.math.BigDecimal(num1);
java.math.BigDecimal n2 = new java.math.BigDecimal(num2);
IDataUtil.put(idc, “value”, n1.subtract(n2).toString());
idc.destroy();
// multiply service - Multiplies two numbers using java.math.BigDecimal.
IDataCursor idc = pipeline.getCursor();
String num1 = IDataUtil.getString(idc, “num1”);
String num2 = IDataUtil.getString(idc, “num2”);
java.math.BigDecimal n1 = new java.math.BigDecimal(num1);
java.math.BigDecimal n2 = new java.math.BigDecimal(num2);
IDataUtil.put(idc, “value”, n1.multiply(n2).toString());
idc.destroy();
// divide service
// Divides two numbers using java.math.BigDecimal. The
// caller can control rounding and scale (number of decimal
// places).
// The default rounding mode is 6 (ROUND_HALF_EVEN).
// The default scale of the result is num1.scale(). For
// example, num1=42 and num2=7.5 returns 6 (5.6 rounded up).
// Use the constants from java.math.BigDecimal for roundingMode.
// The values are:
// 0 ROUND_UP
// 1 ROUND_DOWN
// 2 ROUND_CEILING
// 3 ROUND_FLOOR
// 4 ROUND_HALF_UP
// 5 ROUND_HALF_DOWN
// 6 ROUND_HALF_EVEN
// 7 ROUND_UNNECESSARY
IDataCursor idc = pipeline.getCursor();
String num1 = IDataUtil.getString(idc, “num1” );
String num2 = IDataUtil.getString(idc, “num2” );
int scale = IDataUtil.getInt(idc, “scale”, -1);
int roundingMode = IDataUtil.getInt(idc, “roundingMode”, java.math.BigDecimal.ROUND_HALF_EVEN);
java.math.BigDecimal n1 = new java.math.BigDecimal(num1);
java.math.BigDecimal n2 = new java.math.BigDecimal(num2);
java.math.BigDecimal result;
if(scale == -1)
result = n1.divide(n2, roundingMode);
else
result = n1.divide(n2, scale, roundingMode);
IDataUtil.put(idc, “value”, result.toString());
idc.destroy();
// round service
// Uses java.math.BigDecimal to round a number. This lets
// the caller control rounding and scale (number of decimal
// places).
// If scale not provided, no effect–num1 is returned unchanged.
// The default rounding mode is 6 (ROUND_HALF_EVEN).
// Use the constants from java.math.BigDecimal for roundingMode.
// The values are:
// 0 ROUND_UP
// 1 ROUND_DOWN
// 2 ROUND_CEILING
// 3 ROUND_FLOOR
// 4 ROUND_HALF_UP
// 5 ROUND_HALF_DOWN
// 6 ROUND_HALF_EVEN
// 7 ROUND_UNNECESSARY
IDataCursor idc = pipeline.getCursor();
String num1 = IDataUtil.getString(idc, “num1”);
int scale = IDataUtil.getInt(idc, “scale”, -1);
int roundingMode = IDataUtil.getInt(idc, “roundingMode”, java.math.BigDecimal.ROUND_HALF_EVEN);
java.math.BigDecimal n1 = new java.math.BigDecimal(num1);
if(scale != -1)
n1 = n1.setScale(scale, roundingMode);
IDataUtil.put(idc, “value”, n1.toString());
idc.destroy();
[/highlight]
Create separate Java services for each of these. Feel free to post any questions if anything is unclear.