Opened 4 years ago
Last modified 4 years ago
#279 new defect
PL/I generates incorrect code for divide operation specifying truncate or floor of quotient
| Reported by: | Gary Dixon | Owned by: | Eric Swenson |
|---|---|---|---|
| Priority: | major | Milestone: | |
| Component: | Administration | Version: | |
| Keywords: | Cc: |
Description
I am trying to implement an algorithm that wants the integer part of a division result, using float dec(59) data variables for dividend, divisor and quotient. The PL/I compiler generates code that ALWAYS rounds up the quotient, no matter what builtin functions surround the divide operation.
bad_divide:
proc();
dcl (dividend, divisor, product, quotient, quotient_t, quotient_f, quotient_d) float dec(59);
dcl (divide, floor, trunc) builtin;
dcl ioa_ entry() options(variable);
divisor = 8.;
dividend = 8.0779356694631608874161005084957309918536338955163955688476e+058;
quotient = dividend / divisor;
product = divisor * quotient;
if product > dividend then
call ioa_( "quotient of divide was rounded up.");
dividend = 8.0779356694631608874161005084957309918536338955163955688476e+058;
quotient_t = trunc( dividend / divisor );
product = divisor * quotient_t;
if product > dividend then
call ioa_( "quotient using trunc was rounded up.");
dividend = 8.0779356694631608874161005084957309918536338955163955688476e+058;
quotient_f = floor( dividend / divisor );
product = divisor * quotient_f;
if product > dividend then
call ioa_( "quotient using floor was rounded up.");
dividend = 8.0779356694631608874161005084957309918536338955163955688476e+058;
quotient_d = divide( dividend, divisor, 59 );
product = divisor * quotient_d;
if product > dividend then
call ioa_( "quotient using divide was rounded up.");
end bad_divide;
Results from the bad_divide program prove that the quotient is being rounded up, because the divisor * quotient value is greater than the dividend.
bad_divide quotient of divide was rounded up. quotient using trunc was rounded up. quotient using floor was rounded up. quotient using divide was rounded up.
In each case, the PL/I compiler generates code which does the divide operation, and is followed by an MVN to move the temporary result WITH ROUNDING to the quotient variable. It then calls whatever built-in function was specified to process this rounded-up result.
Code for the simplest division (without a surrounding built-in function) is shown below.
STATEMENT 1 ON LINE 11
quotient = dividend / divisor;
000104 aa 100 100 227 500 dv3d (pr),(pr),(pr)
000105 aa 6 00120 00 0075 desc9fl pr6|80,61 divisor
000106 aa 6 00100 00 0075 desc9fl pr6|64,61 dividend
000107 aa 6 00260 00 0077 desc9fl pr6|176,63
000110 aa 000 300 300 500 mvn (pr),(pr),round
000111 aa 6 00260 00 0077 desc9fl pr6|176,63
000112 aa 6 00160 00 0075 desc9fl pr6|112,61 quotient
Use of eis_tester shows that the dv3d instruction is generating the expected quotient with two fractional places added to the end to accommodate possible rounding. But the compiler ALWAYS adds a mvn instruction with ,round specified instead of conditionally doing the rounding unless suppressed by use of a trunc or floor built-in function.
The following eis_tester script shows the dv3d instruction and its result.
bad_divide_et_script 02/20/22 1431.5 pst Sun
inst dv3d -nt "divide using 3 arguments"
-mf1 ar
-mf2 ar
-mf3 ar;
desc 1 -sd f -nn 61; /* float dec(59) divisor */
desc 2 -sd f -nn 61; /* float dec(59) dividend */
desc 3 -sd f -nn 63; /* float dec(61) quotient */
data 1 "+" (58) "0" "8" 000; /* divisor = 8.0 */
data 2 "+80779356694631608874161005084957309918536338955163955688476" 000;
/* dividend = 8.0779356694631608874161005084957309918536338955163955688476e+058 */
data 3 "+10097419586828951109270125635619663739817042369395494461060" 000;
/* quotient = 1.0097419586828951109270125635619663739817042369395494461060e+058 */
Results of this script are shown below:
eis_tester bad_divide_et_script -long
ET
TEST 1 (dv3d)
Test Description: divide using 3 arguments
Eis instruction: ( 354|4000 ) Ind Desc.
- - - -- - - -
100100227500
100010000075
200020000075
300030000077
Pointer Registers: ( 354|20 )
pr0 - pr3 77777|1 361|1770 362|1760 363|1750
pr4 - pr7 77777|1 77777|1 77777|1 77777|1
Test Indicators: ( 354|111 )
000000000200
This test will take 0 page faults.
data field 1 ( 361|2000 )
053060060060 060060060060 060060060060 060060060060
060060060060 060060060060 060060060060 060060060060
Previous line repeated 1 time.
060060060060 060060060060 060060060070 000
data field 2 ( 362|2000 )
053070060067 067071063065 066066071064 066063061066
060070070067 064061066061 060060065060 070064071065
067063060071 071061070065 063066063063 070071065065
061066063071 065065066070 070064067066 000
data field 3 ( 363|2000 )
Result data field initialized to all zero bits.
test data ( 354|23776 )
xxxxxxxxxxxx xxxxxxxxxxxx 053061060060 071067064061
071065070066 070062070071 065061061060 071062067060
061062065066 063065066061 071066066063 067063071070
061067060064 062063066071 063071065064 071064064066
061060066060 000xxxxxxxxx xxxxxxxxxxxx xxx
Data resulting from test ( 1 - dv3d ) is incorrect.
result data ( 363|1776 )
xxxxxxxxxxxx xxxxxxxxxxxx 053061060060 071067064061
071065070066 070062070071 065061061060 071062067060
061062065066 063065066061 071066066063 067063071070
061067060064 062063066071 063071065064 071064064066
061060065071 065060376xxx xxxxxxxxxxxx xxx
*** TEST NOTES: divide using 3 arguments ***
Note that the result data represents the value:
+1009741958682895110927012563561966373981704236939549446105950e-02
If the trunc built-in was permitted to remove the fractional digits before rounding, this correct integer value would be obtained:
+10097419586828951109270125635619663739817042369395494461059
Change History (1)
comment:1 by , 4 years ago
| Summary: | PL/I generates incorrect code for divide operation specification truncate or floor of quotient → PL/I generates incorrect code for divide operation specifying truncate or floor of quotient |
|---|
