Subject: Re: EVAL(H) Question From: Scott Klement Date: Mon, 10 Aug 2009 15:24:45 -0500 List-archive: List-help: List-id: RPG programming on the IBM i / System i List-post: List-subscribe: , List-unsubscribe: ,

Hi Jeff,

I think EVAL(R) is probably better in the long run. %DEC() is great if you fully understand the problem -- but you don't know who will work on this program next, or whether they'll understand how to change the code with %DEC() so that it'll work with their updated version, etc, etc.

So I would recommend using EVAL(R) or even the H-spec keyword EXPROPTS(*RESDECPOS).

Jeff Young wrote:
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