I'm trying to convert some AS400
/RPG
code into Java
.
I was able to find an example online that mirrored what I am seeing in the code:
d elevensix s 11 6 inz(26285.88991)
d seventwo s 7 2
c eval(h) seventwo = elevensix
c eval *inlr = *on
I have written code in Java
and I am finding that the results of the rounding I see in the RPG
code, it is not matching the type of rounding I see in Java
. Here is a sample of the rounding I am doing in Java
:
private Long roundAmount(Double amount) {
return Math.round(amount);
}
In practice my code generates results that match up to the results from the RPG
code however I am finding examples which are inconsistent in the logic; some which round up as expected and others that don't.
I have worked heavily with Java; this is my first foray into RPG
. I'm honestly not even sure where to begin. For example, in the RPG
code above; how exactly is it working? I see the results of the operation being put into a variable marked with 2 decimal places; is the rounding implicit? Searching online I find the following definition for how Java handles rounding:
The Math.round() method in Java is used to round a number to its closest integer. This is done by adding 1/2 to the number, taking the floor of the result, and casting the result to an integer data type.
Honestly this is clear and concise. I have not found a comparable explanation for how it works in RPG
; to be clear this is programming on an AS400 which uses RPG
, but a much older version than what I believe the current standard is. However an explanation even for the modern implementation would be a start.
The RPG code you posted does a different thing than your Java code.
The Java code transform a Double
to a Long
, while the RPG code is rounding a number with 6 decimals to a number with 2 decimals.
In particular, elevensix
is a number with 11 digits which 6 of them are for the decimal part and 5 of them for the integer part; seventwo
is a number with 7 digits which 2 of them are for the decimal part and 5 of them for the integer part.
eval(h)
is copying the value of elevensix
into seventwo
and rounding it to 2 decimal digits with "half-adjust" logic (that's what the "h" stand for, without it the decimals would be truncated).
From the RPG documentation (that you can find also in PDF format) and in particular here:
Half-adjusting is done by adding 5 (-5 if the field is negative) one position to the right of the last specified decimal position in the result field.
Which to me seems similar to what Math.round
does, but generalized to any decimal position.
Also it would correspond to the Java Math RoundingMode.HALF_UP.
Since you didn't provide some actual examples that generate the inconcistencies it's difficult to give you a definitive solution.
Anyway, that RPG code in Java could be replicated with BigDecimals with the method setScale
like this:
double result = new BigDecimal(amount.toString())
.setScale(2, RoundingMode.HALF_UP)
.doubleValue();
You might also consider to use Apache Commons Math method round
which, looking at the implementation, does pretty much the same thing.
Your problem could also be caused by the limited precision of Double and in that case you should just use BigDecimals, see Double vs. BigDecimal?.