AS / 400:使用COMPUTE函数,结果与不同的字段定义不一致

时间:2013-01-11 06:36:34

标签: ibm-midrange cobol

在AS / 400中使用COMPUTE功能时遇到了一个神秘的问题。

方案如下:

01  WSAA-AMOUNT-A               PIC S9(15)V9(02) COMP-3.
01  WSAA-AMOUNT-B-01            PIC S9(16)V9(02) VALUE 0.
01  WSAA-AMOUNT-B-02            PIC S9(13)V9(05) VALUE 0.
01  WSAA-AMOUNT-C               PIC S9(16)V9(02) VALUE 0.
01  WSAA-RESULT                 PIC S9(15)V9(02) VALUE 0.

MOVE 2500.87             TO WSAA-AMOUNT-A. 
MOVE 12285               TO WSAA-AMOUNT-B-01.
MOVE 12285               TO WSAA-AMOUNT-B-02.
MOVE 4387.5              TO WSAA-AMOUNT-C. 

COMPUTE WSAA-RESULT ROUNDED = (WSAA-AMOUNT-A / ( WSAA-AMOUNT-B-01 + WSAA-AMOUNT-C) * 100 ).
DISPLAY WSAA-RESULT.

COMPUTE WSAA-RESULT ROUNDED = (WSAA-AMOUNT-A / ( WSAA-AMOUNT-B-02 + WSAA-AMOUNT-C) * 100 ).
DISPLAY WSAA-RESULT.

结果让我感到惊讶,第一个公式的结果= 14.90 而第二个变得= 15

听起来后者更符合逻辑,如2500.87 /(12285 + 4387.5)* 100 = 14.99997001。 我希望在舍入后第一个结果的结果也应该是15。

有谁知道这些不一致结果的根本原因是什么?

1 个答案:

答案 0 :(得分:4)

取得的成果为14.90和15.00。

COMPUTE形成不良。当乘以100时,尽可能早地进行,因为如果你最后这样做,两个小数位消失(当除以100时,最后做,所以你不要在早期丢失有效数字)。

它不仅适用于100,所以请考虑一下。乘以第一,除最后,无论涉及什么值。除非在最终答案中需要五个小数位,否则完全没有必要使用具有五个小数位的字段来获得“正确”的答案。

计算机不是计算器或电子表格。它根据您的要求使用中间结果,而不是其他为您提供大量小数位的结果。使用您使用的字段中的小数位数要求小数精度。

了解正在发生的事情的一个关键是精细手册。另一个是实验。这通常可以作为一般答案。

COMPUTE WSAA-RESULT ROUNDED = 
                  (WSAA-AMOUNT-A / ( WSAA-AMOUNT-B-01 + WSAA-AMOUNT-C) * 100 )

显示WSAA-RESULT。得到答案14.90(十四点九零)。

COMPUTE WSAA-RESULT = 
                  (WSAA-AMOUNT-A / ( WSAA-AMOUNT-B-01 + WSAA-AMOUNT-C) * 100 )

显示WSAA-RESULT。得到答案14.00(十四点零零),删除ROUNDED。

COMPUTE WSAA-RESULT ROUNDED = 
                  (WSAA-AMOUNT-A / ( WSAA-AMOUNT-B-02 + WSAA-AMOUNT-C) * 100 )

显示WSAA-RESULT使用五位小数,得到15.00(十五点零 - 零)“正确”的“预期”答案。

记住,你在最后乘以100.所以在此之前,这些值是0.149(小数点后三位),0.14(小数点后两位)和14.99999n(六位小数,我不打算进行计算再次,所以我把第六个留下了“n”)。

为什么有三位,二位和六位小数?这六个是因为B-02(有五个地方,加上一个用于ROUNDED,它将所需的小数位数增加一个,因此可以计算ROUNDED),两个因为B-01(带有两个小数位) )三者是因为B-01和ROUNDED。

这是一个经过重新设计的COMPUTE,有三个版本:

COMPUTE WSAA-RESULT ROUNDED =  ( ( WSAA-AMOUNT-A * 100 )
                               / ( WSAA-AMOUNT-B-01 
                                 + WSAA-AMOUNT-C ) ) 

COMPUTE WSAA-RESULT         =  ( ( WSAA-AMOUNT-A * 100 )
                               / ( WSAA-AMOUNT-B-01 
                                 + WSAA-AMOUNT-C) ) 

COMPUTE WSAA-RESULT ROUNDED = ( ( WSAA-AMOUNT-A * 100 ) 
                              / ( WSAA-AMOUNT-B-02 
                                + WSAA-AMOUNT-C) ) 

结果为15.00,14.99和15.00。

这是Enterprise Cobol。似乎OpenCobol使用了不同的中间结果,可能会记录在案。

以下是关于中间结果的企业Cobol编程指南:

“要了解有关中间结果的此信息,您需要了解以下术语。 ... d中间结果所携带的小数位数。 (如果使用ROUNDED短语,如果需要,可以携带一个小数位以保证准确性。) dmax在特定声明中,以下项目中最大的一项: v最终结果字段所需的小数位数 v为任何操作数定义的最大小数位数, 除非是除数或指数 v任何函数操作数“

的外部-dmax

"Operation ... Decimal places
+ or - ... d1 or d2, whichever is greater
* ... d1 + d2
/ ... (d2 - d1) or dmax, whichever is greater"

对于“错误”示例,加法得到两个小数位(d1和d2都是两个用于加法),除法得到三个小数位(dmax是三个),乘法得到三个(两个+零+一个)对于ROUNDED)。在尝试舍入之后的最终答案(它将永远不会运行,因为两个低位小数由于乘以100而总是为零),被截断为两个小数位。

对于ROUNDED B-01,dmax为3(两个位置的结果字段,加上一个用于舍入)。对于普通的B-01,dmax是两个。对于ROUNDED B-02,dmax为6。

注意,不仅显示的示例错误。 ROUNDED从不在问题的第一个示例中运行,并且总是丢弃一个有效小数,因此您只能在舍入前的答案为十分之一时获得正确的答案。然后,这些正确的答案将被另外九个答案掩盖,这些答案由于截断而变得相同。

如果你总是写有效的COMPUTE,你就不会遇到问题。 ROUNDED仅对最终结果进行操作。如果您需要任何中间字段ROUNDED,请单独计算并在新计算中使用结果。

COMPUTE有效。 COMPUTE不像计算器/电子表格那样运行。也没有任何其他Cobol动词(它们是动词不是函数)。考虑如何编写COMPUTE,以免失去意义。阅读手册。实验。重复直到正确并理解。