0

我正在研究这个 RosettaCode 挑战的蛮力实现。我希望能够处理比 USAGE BINARY-DOUBLE 更大的数字,所以我写了一个简单的 bignum 例程来添加。

如果我想将自己限制在一定数量的迭代中,并且该数量大于 9(18),那么这很棘手。所以我想到了在数组的特定元素上使用 88 的想法,因此下面的代码。

       03  DIGITS1 OCCURS 40 TIMES PIC 9.
       03  FILLER REDEFINES DIGITS1.
           05 FILLER pic 9999999999.
           05 FILLER pic 999999999.
           05 filler pic 9.
               88 EOR value 1.
           05 filler pic 9999999999.
           05 filler pic 9999999999.

所以我仍然想知道这是否是唯一的方法,或者当我达到 10 ^ 20 时是否有其他处理方式。

这是完整的“解决方案”。这是一团糟,但它几乎工作。

   identification division.
   program-id. Program1.

   data division.
   working-storage section.
   01  COUNTER.
       03  DIGITS1 OCCURS 40 TIMES PIC 9.
       03  FILLER REDEFINES DIGITS1.
           05 filler pic 9999999999.
           05 FILLER pic 9999999999.
           05 filler pic 9999999999.
           05 filler pic 999.
           05 filler pic 9.
               88 EOR value 1.
           05 filler pic 999999.

   01  INCREMENTOR.
       03  DIGITS1 OCCURS 40 TIMES PIC 9.

   01  ACCUMULATOR.
       03  DIGITS1 OCCURS 40 TIMES PIC 9.

   01  IN-NUMBER   usage binary-double unsigned.
   01  I               USAGE BINARY-DOUBLE UNSIGNED.
   01  N               USAGE BINARY-DOUBLE UNSIGNED.
   01  THREE-COUNTER   USAGE BINARY-CHAR value 1.
       88 IS-THREE VALUE 3.
   01  FIVE-COUNTER    USAGE BINARY-CHAR value 1.
       88 IS-FIVE VALUE 5.
   01  ANSWER pic x(40).       
   procedure division.
       initialize COUNTER ACCUMULATOR incrementor.
   10-MAIN-PROCEDURE.
       move 1 to IN-NUMBER.
       call "MOVENUMTOBIGNUM" using by content in-number 
           by reference incrementor.
       move 1 to IN-NUMBER.
       call "MOVENUMTOBIGNUM" using by content in-number 
           by reference counter.
       PERFORM 20-INNER-LOOP WITH TEST AFTER UNTIL eor.
       move ACCUMULATOR to ANSWER.
       inspect answer REPLACING LEADING '0'
        by space.
       DISPLAY answer.
       STOP RUN.
   20-INNER-LOOP.
       IF IS-THREE OR IS-FIVE
           call "ADDBIGNUMS" using by content counter
            by reference accumulator
           IF IS-THREE
               MOVE 1 TO THREE-COUNTER
           ELSE
               ADD 1 TO THREE-COUNTER
           END-IF
           IF IS-FIVE
               MOVE 1 TO FIVE-COUNTER
           ELSE    
               ADD 1 TO FIVE-COUNTER
           END-IF
       ELSE
           ADD 1 TO FIVE-COUNTER END-ADD
           ADD 1 TO THREE-COUNTER END-ADD
       END-IF.
       call "ADDBIGNUMS" using by content INCREMENTOR 
        by reference counter.
       EXIT.
   end program Program1.

   identification division.
   PROGRAM-ID. MOVENUMTOBIGNUM.
   ENVIRONMENT DIVISION.
   DATA DIVISION.
   WORKING-STORAGE SECTION.
   01  num-MOD   usage binary-CHAR.
   01  num-DIV   usage binary-DOUBLE unsigned.
   01  IN-COUNTER  usage binary-char.
   LINKAGE SECTION.
   01  num usage binary-double.
   01  BIGNUM.
       03  DIGITS1 OCCURS 40 TIMES PIC 9.

   PROCEDURE DIVISION USING NUM BIGNUM.
   10-MOVE.
       move 40 to IN-COUNTER.
       perform until num = 0
           divide num by 10 
               giving num-DIV 
               REMAINDER num-MOD
           end-divide
           move num-MOD to DIGITS1 of BIGNUM(IN-COUNTER)
           move NUM-DIV to NUM
           subtract 1 from IN-COUNTER end-subtract
       END-PERFORM.
       GOBACK.
   END PROGRAM MOVENUMTOBIGNUM.

  *Add Bignum to Bignum, modifying second Bignum in situ
   identification division.
   program-id. ADDBIGNUMS.
   DATA DIVISION.
   WORKING-STORAGE SECTION.
   01 IN-COUNTER usage binary-char.
   01  ADD-FLAG    pic 9.
       88 STILL-ADDING VALUE 0.
       88 DONE-ADDING VALUE 9.
   01  CARRIER usage binary-char.
   01  REGISTER-A usage binary-char.

   LINKAGE SECTION.
   01  BIGNUM1.
       03  DIGITS1 OCCURS 40 TIMES PIC 9.
   01  BIGNUM2.
       03  DIGITS1 OCCURS 40 TIMES PIC 9.

   PROCEDURE DIVISION USING BIGNUM1 BIGNUM2.
   10-ADD-WITH-CARRY.
       move zero to CARRIER.
       move 40 to IN-COUNTER.
       move zero to ADD-FLAG.
       perform until DONE-ADDING
           add DIGITS1 of BIGNUM1(IN-COUNTER)
           DIGITS1 of BIGNUM2(IN-COUNTER)
           CARRIER GIVING REGISTER-A 
           END-ADD
           move zero to CARRIER
           if REGISTER-A > 9 
               divide REGISTER-A by 10 
                   giving CARRIER 
                   remainder REGISTER-A
               end-divide
            else
               if REGISTER-A = zero
                   move 9 to ADD-FLAG
               END-IF
            end-if
            if STILL-ADDING
               move REGISTER-A to DIGITS1 of BIGNUM2(IN-COUNTER)
               subtract 1 from IN-COUNTER end-subtract
            end-if
       END-PERFORM.
       goback.
   END PROGRAM ADDBIGNUMS.
4

1 回答 1

1

虽然你似乎已经不喜欢这个结构,但我会坚持下去。它也适用于您的结构。不需要 REDEFINES 或那些其他 FILLER。

   05  FILLER.
       10  FILLER OCCURS 40 TIMES.
            15  DIGITS1                   PIC 9.
                88  DIGITS1-MEANS-SOMETHING
                                          VALUE 1.

01  NAME-THAT-REVEALS-INFORMATION BINARY  PIC 9(4).

    IF DIGITS1-MEANS-SOMETHING
        ( NAME-THAT-REVEALS-INFORMATION )
        do some stuff
    END-IF

我已将您的 PIC 9 更改为 PIC X。除非您进行计算,否则永远不需要将字段定义为 9 来表示“数字”。如果一个字段碰巧包含数字,或者碰巧在其名称中包含单词 number 或类似的东西,请不要被欺骗将其定义为数字。

随之而来的是额外的(生成的)代码,它的含义是“用这个来完成数字的东西”,所以会产生误导。如果/当您需要对输出进行“数字编辑”时,此时总会有 REDEFINES。不必有这些其他成本来实现这一点。

我现在已经恢复到您的 PIC 9,因为在您编辑之后,我可以看到您正在使用它进行计算 :-)

于 2015-11-09T06:53:08.610 回答