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 Gary Dixon, 4 years ago

Summary: PL/I generates incorrect code for divide operation specification truncate or floor of quotientPL/I generates incorrect code for divide operation specifying truncate or floor of quotient
Note: See TracTickets for help on using tickets.