Thanks Scott,
I had a feeling it was something like that.
When you explained the "internal workings" of the operation, it made even more sense.
In your professional opinion, would it be better to use the %dec bif or the Eval(R) op-code.
Thanks,
Jeff Young
Sr. Programmer Analyst
IBM -e(logo) server Certified Systems Exper - iSeries Technical Solutions V5R2
IBM Certified Specialist- e(logo) server i5Series Technical Solutions Designer V5R3
IBM Certified Specialist- e(logo)server i5Series Technical Solutions Implementer V5R3
________________________________
From: Scott Klement <rpg400-l@xxxxxxxxxxxxxxxx>
To: RPG programming on the IBM i / System i <rpg400-l@xxxxxxxxxxxx>
Sent: Monday, August 10, 2009 2:00:10 PM
Subject: Re: EVAL(H) Question
Hi Jeff,
By default, RPG uses something called "the Maximum Digits rule" for
decimal precision in the intermediate results of an expression. Which
basically means that RPG needs to create temporary (under-the-covers)
variables for each step in calculating your expression.
First thing RPG has to do is take Srp_Value_Rate and divide it by 100.
So Srp_Value_Rate is a 5,2 field... and 100 is a 3-digit field. What's
the maximum possible digits to the left of the decimal place when
dividing a 5,2 by a 3,0 field? still 3 digits, right? There are no
decimal places in a 3,0 field, so division can't make the number higher.
So, since you can only have max 3-digits to the left of the decimal
place, the intermediate result will be 30,27 by default (30 digits with
27 decimal places). And if Srp_Value_rate=40, that means you'll have
Srp_Value_Rate / 100
000.400000000000000000000000000
Now subtract that value from 1. So you have a 1,0 field subtracting a
30,27 field? Whats the max digits to the left of the decimal place?
it's one higher, because it could potentially overflow into a 4th digit
(-9 - -999 = -1018) so you'll now have a 30,26 intermediate result
1 - (Srp_Value_Rate / 100)
000.600000000000000000000000000
This is silly because you don't *need* 26 decimal places here -- but RPG
thinks you do. You really only need 2.
Now RPG needs to divide Current_Srp_Value by that intermediate result.
(Dividing by an intermediate result is often messy because RPG maxes out
the decimal places using the *MAXDIGITS style, which means the digits to
the left goes through the roof).
So you hae a 11,4 field divided by a 30,26 field. How many maximum
digits to the left? The maximum possible value of a 11,4 divided by a
30,26 would be yikes, 37 digits to the left of the decimal place? That
won't fit into RPG's default 30 digit intermediate result fields, so
it'll eliminate all of the decimal places so that, at least the whole
numbers will be preserved.
current_base / (1 - (Srp_Value_Rate / 100))
000000000000000000000000000004
So that's what RPG is doing under the covers -- and is the reason why
you're having this problem. At first glance, it might sound like
increasing the size of the intermediate field from 30 digits to 63
digits might help -- but it won't. Because the intermediate result of
the first two calculations will end up being 59 decimal places instead
of 26, thus creating the same problem (just in a larger field)
Personally, I'd solve the problem by doing this:
eval(h) current_srp_value = Current_base
/ %dec(1 - (Srp_Value_rate/100): 6: 2);
I've used the %DEC() BIF to control the size of the intermediate result.
I've told RPG that the intermediate result of the first two steps of the
expression should be a 6,2 field -- that way, it won't calculate 26
decimal positions in the intermdiate result.
Then the final division results in a maximum of 13 digit intermediate
field, leaving 17 decimal positions, more than enough space for your
purposes, and the EVAL(H) then rounds it off to 2 decimal places, as
you'd expect.
That's the optimal solution -- but requires someone to sit down and
figure out what RPG is doing in order to know where to put the %DEC()
and know how big to make it. So it requires a total geek like me. :) I
mean, really, who does that???
An easier solution is to specify EXPROPTS(*RESDECPOS) on the H-spec, or
the R extender on the EVAL. In either case, that tells RPG not to drop
all of it's decimal places for it's intermediate result fields.
Instead, it'll force the intermediates to have as many decimal places as
the result.
eval(hr) current_srp_value = Current_base
/ (1 - (Srp_Value_rate/100));
Have a lovely day.
Jeff Young wrote:
I have the following instruction in my program:
Eval(H) Current_SRP_Value =
Current_Base / (1 - (SRP_Value_Rate / 100));
ATTR current_srp_value
TYPE = PACKED(9,2), LENGTH = 5 BYTES
ATTR current_base
TYPE = PACKED(11,4), LENGTH = 6 BYTES
ATTR srp_value_rate
TYPE = PACKED(5,2), LENGTH = 3 BYTES
EVAL SRP_Value_Rate
SRP_VALUE_RATE = 040.00
EVAL Current_Base
CURRENT_BASE = 0000002.7938
The result being returned is 4.00.
When using a calculator, I get the value 4.6563333333333333.
I would expect the result to be 4.66.
Do I need to specify Eval(RH) to get the desired result?
I am on V5R4.
Thanks,
Jeff Young
Sr. Programmer Analyst
IBM -e(logo) server Certified Systems Exper - iSeries Technical Solutions V5R2
IBM Certified Specialist- e(logo) server i5Series Technical Solutions Designer V5R3
IBM Certified Specialist- e(logo)server i5Series Technical Solutions Implementer V5R3
As an Amazon Associate we earn from qualifying purchases.