On 2011/12/8 2:57 PM, James Horn wrote:
I am changing some old code and there seems to be a difference in how the
divide statement works.
C YEAR DIV 4 AVEQTR
C LSTQTR SUB AVEQTR DIFQTR
C DIFQTR DIV AVEQTR RATIO
C EVAL RATIO = DIFQTR / AVEQTR
/FREE
AVEQTR = YEAR / 4;
DIFQTR = LSTQTR - AVEQTR;
RATIO = DIFQTR / AVEQTR;
RATIO = (LSTQTR - (AVEQTR)) / (AVEQTR) ;
RATIO = (LSTQTR - AVEQTR) / AVEQTR ;
RATIO = (LSTQTR - (YEAR /4)) / (YEAR /4) ;
When you use DIV and SUB, you are choosing the exact length and decimals
for the temporary result value. When you use / and -, you are letting
the compiler choose.
For addition, multiplication and subtraction, the sizes that the
compiler picks for temporaries are related to the sizes of the operands.
But for division, the size of the temporary is always the maximum number
of digits. If the divisor of the division only has a few decimal places,
then the division temporary only has a few integer places, and many
decimal places, so the result is very accurate. But if the divisor of
the division has many decimal places, then the division temporary has
many integer places, and only a few decimal places, so the result is
less accurate.
With your first five free-form assignments, you only have one division,
so the sizes that the compiler is choosing for its temporaries works
fine. The temporary for (LSTQTR - AVEQTR) / AVEQTR would be 63 digits,
with lots of decimal places, probably over 30 decimals.
With your last free-form assignment, you are dividing by a division.
something / (YEAR / 4)
(YEAR / 4) has 63 digits and probably over 50 decimal places.
(something / (YEAR / 4))
has 63 digits, but because (YEAR / 4) has so many decimal places, the
compiler assume that (YEAR / 4) might be 0.000000000...001 (and dividing
by that gives a huge number). So the compiler gives the temporary as
many integer places as possible to avoid overflow. So the temporary used for
(something / (YEAR / 4))
probably doesn't have any decimal places at all.
As Brian said, it's a good idea to understand how the compiler
determines the sizes of its temporaries. Working through your problem
statement to figure out the sizes of the temporaries will be a useful
exercise, since it's not too long.
And it's usually a good idea to use the (R) extender or
EXPROPTS(*RESDECPOS), but you should understand how those work too, so
it would be a good idea to work that problem statement both ways.
Besides using the (R) extender or EXPROPTS(*RESDECPOS), you can also
control the size of the temporary result using %DEC, so you could make
your EVAL work exactly the same as your DIV SUB DIV by using %DEC. (Or
%DECH if you had been using half-adjust on your DIV SUB DIVs.)
But as you can see, this gets very ugly very fast.
RATIO = (LSTQTR - (YEAR /4)) / %DEC(YEAR /4 : 9 : 2) ;
Or instead of dividing YEAR by 4, you could multiply by .25, avoiding
dividing by a division.
RATIO = (LSTQTR - (YEAR * .25)) / (YEAR * .25) ;
But it's also sometimes a good idea to use your own temporary and two
statements, just for clarity. This might be easier to understand than
the single statement.
AVEQTR = YEAR / 4;
RATIO = (LSTQTR - AVEQTR) / AVEQTR;
As an Amazon Associate we earn from qualifying purchases.