﻿id	summary	reporter	owner	description	type	status	priority	milestone	component	version	resolution	keywords	cc
279	PL/I generates incorrect code for divide operation specifying truncate or floor of quotient	Gary Dixon	Eric Swenson	"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
}}}


"	defect	new	major		Administration				
