Tips, Tricks, and Techniques
Last update: 30 April 2004
Dividing
"Arithmetic Curiosity"
We have come across a very interesting - and very disturbing -
phenomenon in
Natural regarding its computational functionality.
We run the following program (simplified for ease of reading):
DEFINE DATA
LOCAL
1 ##A (N9.2) INIT <1000000.02>
1 #BB (N3.3) INIT <3.606>
1 #CC (N3.3) INIT <4.143>
1 #DD (N5.4) INIT <143.7>
1 #EE (N5.4) INIT <3.5>
1 #FF (N6.4) INIT <152.3>
1 #GG (N5.4) INIT <3.5>
1 #HH (P13.2)
END-DEFINE
*
COMPUTE #HH =
##A * ( ( 1 + #BB / 100 ) * #GG / #EE
- (1 + #CC / 100 ) * #FF / #DD )
WRITE #HH
END
and receive the following result:
NEXT
Page 1
-67300.60
Then we make the following change to the program (adding the field #II
as
a temporary receiving field):
DEFINE DATA
LOCAL
1 ##A (N9.2) INIT <1000000.02>
1 #BB (N3.3) INIT <3.606>
1 #CC (N3.3) INIT <4.143>
1 #DD (N5.4) INIT <143.7>
1 #EE (N5.4) INIT <3.5>
1 #FF (N6.4) INIT <152.3>
1 #GG (N5.4) INIT <3.5>
1 #HH (P13.2)
1 #II (P13.5)
END-DEFINE
*
COMPUTE #II =
##A * ( ( 1 + #BB / 100 ) * #GG / #EE
- (1 + #CC / 100 ) * #FF / #DD )
ASSIGN #HH = #II
WRITE #HH
END
and re-execute, obtaining the following result:
NEXT
Page 1
-67696.30
Why is there such a large discrepancy in the results? As far as I can
recall
(and have been told), Cobol does not act this way. Is this a bug, or
a known pitfall of Natural that every experienced Natural programmer is
familiar with and knows to avoid?
Regards,
Shlomo Godick
DBA, Mehish Computer Services, Ltd.
15 Lincoln St.
67134 Tel Aviv, Israel
Tel: 972-3-563-4407/4497
Fax: 972-3-561-1342
Email: shlomog@ibm.net
Here is an interseting follow-up to the previous computation problem I
presented yesterday.
As you recall, the program was:
DEFINE DATA
LOCAL
1 ##A (N9.2) INIT <1000000.02>
1 #BB (N3.3) INIT <3.606>
1 #CC (N3.3) INIT <4.143>
1 #DD (N5.4) INIT <143.7>
1 #EE (N5.4) INIT <3.5>
1 #FF (N6.4) INIT <152.3>
1 #GG (N5.4) INIT <3.5>
1 #HH (P13.2)
END-DEFINE
*
COMPUTE #HH =
##A * ( ( 1 + #BB / 100 ) * #GG / #EE
- (1 + #CC / 100 ) * #FF / #DD )
WRITE #HH
END
and we received the following (incorrect) result:
NEXT
Page 1
-67300.60
The Natural programmer that showed me this now informs me that if,
in the calculation, he multiplies by .01 instead of dividing by 100,
as in the following:
DEFINE DATA
LOCAL
1 ##A (N9.2) INIT <1000000.02>
1 #BB (N3.3) INIT <3.606>
1 #CC (N3.3) INIT <4.143>
1 #DD (N5.4) INIT <143.7>
1 #EE (N5.4) INIT <3.5>
1 #FF (N6.4) INIT <152.3>
1 #GG (N5.4) INIT <3.5>
1 #HH (P13.2)
END-DEFINE
*
COMPUTE #HH =
##A * ( ( 1 + #BB * .01 ) * #GG / #EE
- (1 + #CC * .01 ) * #FF / #DD )
WRITE #HH
END
he receives the following (correct) result:
NEXT
Page 1
-67696.30
In other words, while defining all variables with the same precison
helps
to overcome the problem, it is not the real source of the problem.
Rather, the division operation seems to be the culprit. In my opinion
this
is a bug and Natural, like Cobol, should provide internally an
intermediate
work field of sufficient precision to overcome the division operation
problem.
This would have been preferable to rewriting the PC version to compute
the
result incorrectly like the mainframe version (a good example of where
even the zeal for cross-platform compatibility can be misapplied).
This problem really points to a more philosophical problem with Natural.
Natural claims to be a 4GL, yet the need to be aware of precision issues
in simple computations in order to get the correct result reduces it to
a status below that of Cobol. In what other language (aside from
Assembler)
does a programmer have to do this? Remember, I am not talking about
fine-tuning
the code for performance (where looking at precision, packed numbers,
etc.
is appropriate), I'm talking about getting the correct as opposed to
a grossly incorrect result!
Not to mention the public relations aspect. As DBA's, we often find
ourselves
acting as "good will ambassadors" for Adabas and Natural in our
respective
places of work. When the programmer told me that if he had been in
charge of acquiring Natural and had been shown this bug before the
purchase, he would not have acquired it - what was I to say to him?
My opinion only ...
Regards,
Shlomo Godick
Shlomo,
The following may help explain your arithmetic curiosity.
Edmund
0010 * -------+---------+---------+---------+---------+---------+---------+
0020 *
0030 * Dividing
0040 *
0050 * -------+---------+---------+---------+---------+---------+---------+
0060 *
0070 * The number of decimal positions resulting from a division in a
0080 * COMPUTE statement is derived from the first operand (dividend)
0090 * or the first result field. If the first result field has more
0100 * decimal positions than the operands, the number of decimal positions
0110 * in the first result field will be used.
0120 * (NATURAL 2.2 Reference Manual, p 3-87)
0130 *
0140 * -------+---------+---------+---------+---------+---------+---------+
0150 *
0160 DEFINE DATA
0170 *
0180 LOCAL
0190 *
0200 01 #A1 (P1.0) INIT <1>
0210 01 #A2 (P1.4) INIT <1>
0220 01 #B (P1.0) INIT <3>
0230 01 #C (P6.2)
0240 01 #D (P6.6)
0250 *
0260 END-DEFINE
0270 *
0280 * -------+---------+---------+---------+---------+---------+---------+
0290 *
0300 COMPUTE #C = (#A1 / #B) * 1000000
0310 COMPUTE #D = (#A1 / #B) * 1000000
0320 *
0330 WRITE #C #D
0340 *
0350 COMPUTE #C = (#A2 / #B) * 1000000
0360 COMPUTE #D = (#A2 / #B) * 1000000
0370 *
0380 WRITE #C #D
0390 *
0400 * -------+---------+---------+---------+---------+---------+---------+
0410 *
0420 END
0430 *
0440 * -------+---------+---------+---------+---------+---------+---------+