COBOL COMPUTE计算

时间:2014-03-27 06:09:14

标签: cobol

我正在使用以下计算执行独立的Enterprise COBOL程序。我有一个具有多个操作的COMPUTE,另一个具有完整的计算分割。但两种情况下的结果都不同(最后4位数字)。

我使用计算器手动计算了这些,结果与拆分的COMPUTE语句匹配。我通过在中间结果处使用整个答案来尝试计算,并且仅使用最终答案的15位数字,并且在所有中间步骤中仅使用15位数字(没有舍入)。但是这些结果都没有与组合的COMPUTE结果相匹配。

有人可以帮助我理解为什么会有这样的差异。

      05 WS-A              PIC S9(3)V9(15) COMP.
      05 WS-B              PIC S9(3)V9(15) COMP.
      05 WS-C              PIC S9(3)V9(15) COMP.
      05 WS-D              PIC S9(3)V9(15) COMP.
      05 WS-E              PIC S9(3)V9(15) COMP.
      05 WS-RES            PIC S9(3)V9(15) COMP.  
      05 RES-DISP          PIC -9(2).9(16).

       MOVE 3.56784                TO WS-A.
       MOVE 1.3243284234           TO WS-B.
       MOVE .231433897121334834    TO WS-C.
       MOVE 9.3243243213           TO WS-D.
       MOVE 7.0                    TO WS-E.   

       COMPUTE WS-RES = WS-A / WS-B.
       MOVE WS-RES TO RES-DISP.
       COMPUTE WS-RES = WS-RES / WS-C.
       MOVE WS-RES TO RES-DISP.   
       COMPUTE WS-RES = WS-RES / (WS-D + WS-E).
       MOVE WS-RES TO RES-DISP.   
       COMPUTE WS-RES = WS-RES * (WS-C - WS-A) 
       MOVE WS-RES TO RES-DISP.   
       COMPUTE WS-RES = WS-RES + WS-E ** WS-B 
       MOVE WS-RES TO RES-DISP.   
       COMPUTE WS-RES = WS-RES + WS-D.
       MOVE WS-RES TO RES-DISP.   

上次计算的结果= 20.1030727225138740

       COMPUTE WS-RES = WS-A / WS-B / WS-C /
               (WS-D + WS-E) * (WS-C - WS-A) +
               WS-E ** WS-B + WS-D.
       MOVE WS-RES TO RES-DISP.   

计算合并的结果= 20.1030727225138680

2 个答案:

答案 0 :(得分:3)

慢,我知道,但我想我已经知道为什么你用15位小数定义了所有内容。你无法以其他方式工作。

请阅读下方链接中的问题(当然还有答案)。您无需使用输出所需的精度指定所有字段。

重新安排您的COMPUTE。主要COMPUTE之外的指数。首先乘以。然后除。任何添加/减少自然适合。使用括号来准确指定人们如何阅读COMPUTE(编译器不关心它,它会按照它所说的去做,但有时人们不知道他们在说什么)。

如果你这样做(正确),你将获得与你的COMPUTE相同的答案,所有字段都有15位小数。

如果你不这样做,你的COMPUTE(以及复制它时的其他人)将永远是脆弱的,并且在更改时容易出错。

最好将COMPUTE分解为较小的,就像你做的那样,你可以看到哪些值放入你的计算器。当你使字段的大小正确时,你可以做同样的事情。

我将不得不完全重写这一点,因为多次更新会让它变得混乱......在某些时候。

好的,确认。差异是由于计算COMPUTE中的非整数取幂,正如手册所说,然后将COMPUTE中的所有内容(所有中间字段)转换为浮点数,其小数位数比PICture条款中规定的15。

现在有一个诊断消息(已取出取幂)由于乘法,它希望有36位数,但只能有30(ARITH(COMPAT))或31(ARITH(EXTEND))。如果通过此截断高阶数据,则会出现运行时消息。

请注意。使用ARITH(COMPAT)15是有效精度不会丢失的最大有效位数(64位浮点数)。 ARITH(EXTEND)保证精度,但处理开销(128位浮点)。

回到更早......

一直在考虑这个问题。您使用的是18位数,并且您没有提到使用ARITH(EXTEND)作为编译选项,并且没有提到为大型COMPUTE生成的任何诊断消息。这很有趣。

Haven在COBOL中进行了多次取幂,然后只用了整数。所以我查看了手册。由于小部分取幂大型COMPUTE中的所有都是以浮点形式完成的。这并不重要,但这意味着事情的完成精度要高于定义中15位小数的预期。在你的小型COMPUTE中,这种情况不会发生。

我建议从大的COMPUTE中取出取幂,单独计算并简单地将该结果放入大的COMPUTE(一个简单的加法取代取幂)。我怀疑在那个阶段编译器会开始抱怨结果中有效数字的数量。如果是,那么如果您确实丢失了有效数字,则会收到运行时消息。

你应该:

  1. 取出大的COMPUTE中的取幂并用指数的单独COMPUTE的结果替换它
  2. 将每个字段定义为数据所需的最大大小(不是所有内容的最大值)
  3. (可能)从COMP更改为COMP-3,但自己测试
  4. 将所有内容括起来,以便人类读者知道编译器将在
  5. 中执行操作的顺序
  6. 如果您仍然有关于可能在COMPUTE中截断的警告,请查看ARITH(EXTEND)编译器选项,但不要将其作为修复程序使用,只在需要时使用它,并记录其使用情况该计划
  7. 我稍后会尝试确认,但我认为这样可以解决这个问题。

    以下是开始,并且仍然适用于一般情况,尽管与特定问题没有直接关系(问题是强制进入所有内容的较高浮点精度与仅强制进行取幂):

    小COMPUTEs的问题在于你没有按照与大COMPUTE元素相同的顺序执行它们。

    ()不是为了好玩,或者只是将事物分组在一起,它们在计算中确立了优先权。

    还有什么优先权?操作员使用。优先顺序是什么?好吧,你必须在手册中查看,记住它,或者每次忘记时都要熟悉它。嗯....不是一个好建议。

    另外,其他人将处理您编写或更改的程序。他们可能会知道" COMPUTE是如何工作的(我的意思是他们不是,但他们认为他们这样做,所以不会看起来如此)。双重不好的建议。

    ...所以

    使用()并定义您希望完成任务的顺序。

    还要注意你可能失去意义的地方。看看这个,AS/400: Using COMPUTE function, inconsistent results with different field definition,阅读并理解Enterprise COBOL手册的参考部分。

    作为此网站上链接问题的摘要,请先乘以最后一位,以确保中间结果不会丢失有效数字。除非你故意想要丢失数字,否则这些COMPUTE会单独失去重要性,并对代码进行评论,以便没有人修复"它

    在大型机上使用COMP / COMP-4 / BINARY / COMP-5来处理带小数位的字段也很不寻常。对COMPUTEs感到满意后,复制程序并将字段定义更改为COMP-3 / PACKED-DECIMAL。在每个程序的计数器上放一个循环,看看你是否注意到CPU使用率有任何显着差异。

答案 1 :(得分:1)

我通过一些小的改动来复制,编译和运行你的程序:

  • RES-DISP声明为PIC -9(3).9(15)以避免编译器截断警告
  • 添加了新变量WS-EXP PIC S9(3)V9(15) COMP
  • 添加了一个新计算,就像Bill Woodger建议的那样,将指数分解为单独的计算,如下所示:
  COMPUTE WS-EXP = WS-E ** WS-B 
  COMPUTE WS-RES = WS-A / WS-B / WS-C /  
     (WS-D + WS-E) * (WS-C - WS-A) +  
     WS-EXP + WS-D.

此程序中发出的唯一编译器警告是针对上面的第二个COMPUTE语句。消息是:

IGYPG3113-W Truncation of high-order digit positions may occur due to intermediate results exceeding 30 digits

上面的COMPUTE结果与您的碎片计算完全相同:020.103072722513874。 您的一体化COMPUTE语句不会导致编译器警告。但是内部取幂引起了 在整个计算过程中使用的更高精度的中间结果(更少的舍入)产生略微不同 结果:020.103072722513868。

这里有另一个有趣的观察。使用ARITH(COMPAT)我得到的结果与问题中的结果完全相同,使用ARITH(EXTEND)I 对于零碎计算得到020.103072722513877,对于一体化COMPUTE得到020.103072722513874(这与 用ARITH(COMPAT)编译时的零碎计算。

所有这些都表明,在进行复杂计算时,您需要真正研究数字精度,舍入和截断规则。这是 特别是COBOL,因为程序员可以使用不同的数字数据类型。