2014-03-27 528 views
2

我正在执行一个独立的企业COBOL程序,计算如下。我有一个计算多个操作和另一个完整的计算分裂。但是在这两种情况下结果是不同的(最后4位数字)。COBOL COMPUTE计算

我已经使用计算器手动计算了这些值,结果与分割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

+0

我已经更新了答案,有一个微妙的指数,我认为这是你看到的实际问题。通过你所拥有的价值观和计算,我认为排序并不重要。想知道为什么你没有诊断信息,我想我已经发现 –

+0

这种特殊情况是当汇编列表(LIST)可以派上用场。理解编译器生成的代码可以帮助理解结果。优化也可能会造成偏差,但我相信这将成为Enterprise COBOL 5.1的更多问题,因为它使用与C和PL/I相同的代码生成器。对于“有趣”,我会拿你的原始代码并比较生成的代码。您已经从Bill那里得到了一个很好的答案,并且比较了此处显示的所有代码(原始代码和解决方案)中生成的代码,这将有助于您更好地理解编译器的工作方式。 – zarchasmpgmr

回答

3

慢,我知道,但我想我刚刚拿到了,为什么你定义的一切小数点后15位。否则你无法使其工作。

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

重新安排您的计算器。指数在主COMPUTE之外。先乘以。然后划分。任何加法/减法自然适合。使用圆括号来准确指定您希望人们如何阅读COMPUTE(编译器不关心,它会按照所讲的内容进行,但有时候人们不知道他们在说什么)。

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

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

将计算器分解为更小的计算器是一个好主意,就像您一样,以便您可以看到要将哪些值输入计算器。当您将字段设置为正确的尺寸时,您可以做同样的事情。

我将不得不完全重新写这个,因为多个更新使它变得凌乱......在某个时刻。

好的,确认。不同之处在于计算COMPUTE内的非整数指数,如手册所述,然后将COMPUTE中的所有内容(所有中间字段)转换为浮点数,该浮点数的小数位数多于图片条款中规定的15个。

由于乘法的原因,现在有一个诊断消息(已经取幂运算出来),它希望有36位数,但只能有30个(ARITH(COMPAT))或31个(ARITH(EXTEND))。如果高位数据被截断,则会有运行时间消息。

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

回到较早...

一直在想这个。您正在使用18位数字,并且您没有提到将ARITH(EXTEND)用作编译选项,并且未提及为大型COMPUTE生成的任何诊断消息。这很有趣。

在COBOL中没有做过很多指数运算,然后只用了整数。所以我看了一下手册。由于分数指数所有在您的大型COMPUTE中都是以浮点形式完成的。这并不重要,但它意味着事情的执行速度要比定义中小数点后15位的预期要高。在你的小型计算机中,这不会发生。

我建议采取幂出大COMPUTE的,计算的是单独干脆把在大计算该结果(一个简单的加法替换幂)。我怀疑在那个阶段编译器会开始抱怨结果中的有效位数。如果确实如此,那么如果实际上丢失了一个有效数字,则会得到运行时间消息。

您应该:

  1. 取幂走出大COMPUTE,并与幂
  2. 单独COMPUTE的结果替换它的每个字段定义其数据所需的最大尺寸(不最大可能的一切)
  3. (可能)更改为COMP-3 COMP,但测试它自己
  4. Parenthesise一切使人体读者知道的顺序编译器会做的事情在
  5. 如果在COMPUTE中仍然存在有关可能截断的警告,请查看ARITH(EXTEND)编译器选项,但不要将其作为修补程序来使用,只在需要时才使用它,并记录该程序的用法

我会尽量在稍后再确认一下,但我认为这样会把它整理出来。

以下是开始,还适用于一般情况下,虽然没有直接针对具体问题(问题被迫到一切较高的浮点精度VS只能被迫为幂)相关:

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

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

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

另外,其他人将在您编写或更改的程序上工作。他们可能“知道”COMPUTE的工作方式(我的意思是他们不这样做,但认为他们这样做,所以不会查找)。双重不好的建议。

所以....

使用()并确定要在其中做事情的顺序。

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

作为本网站链接问题的摘要,请先乘以最后一位,确保中间结果不会丢失重要数字。除非你故意要丢失数字,在这种情况下,这些计算机会单独失去重要性,并对代码进行评论,以便没有人“修复”它。

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

1

我拷贝,编辑和一个微小的改动运行您的程序:

  • 声明RES-DISPPIC -9(3).9(15)避免编译器截断警告
  • 增加了新的变数WS-EXP PIC S9(3)V9(15) COMP
  • 增加了一个新的计算做的比尔伍德建议通过将幂运算分解成如下单独计算:
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 

上面的计算结果与您的分段计算完全相同:020.103072722513874。 您的所有功能于一身的COMPUTE语句不会导致编译器警告。但是内部取幂导致在整个计算过程中使用更高精度的中间结果(更少的舍入),产生稍有不同的结果:020.103072722513868。

这里还有一个有趣的观察。使用ARITH(COMPAT)我得到的结果与问题完全相同,使用ARITH(EXTEND)I 得到020.103072722513877作为片段计算,020.103072722513874作为所有功能于一身的COMPUTE(与 相同)与ARITH(COMPAT)编译时)。

这一切都表明,您需要在进行复杂计算时真正研究数值精度,舍入和截断规则。由于编程人员可以使用不同的数字数据类型的数量,所以这是 尤其适用于COBOL。