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

标签 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。

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

最佳答案

达到的结果是14.90和15.00。

COMPUTE的格式不正确。乘以100时,请尽早执行,因为如果您最后进行一次,则两个小数位会消失(除以100时,最后要保留小数位,这样就不会早早丢失有效数字)。

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

该计算机不是计算器或电子表格。它使用中间结果取决于您的要求,而不是根据其他结果而为您提供许多小数位。您使用所使用的字段中的小数位数要求十进制精度。

精细手册是了解正在发生的事情的一个关键。另一个是实验。这通常是一个普遍的答案。

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


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

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


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

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


通过使用五个小数位,DISPLAY WSAA-RESULT得到15.00(零点零零)为“正确”“预期”答案。

请记住,您最后乘以100。因此在此之前,值分别为0.149(小数点后三位),0.14(小数点后两位)和14.99999n(小数点后六位),我不再进行计算,因此我将第六个留为“ n”)。

为什么小数点后三,二和六?六个是因为B-02(具有五个位,再加上一个用于ROUNDED,则将所需的小数位增加1,以便可以计算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为3),乘法运算得到三个(ROUNDED为2 + 0 + 1) )。尝试四舍五入后的最终答案(由于两个低位小数由于乘以100而始终为零,因此它将永远不会起作用)被截断为两位小数。

对于ROUNDED B-01,dmax为3(两个字段的结果字段加一个四舍五入)。对于普通的B-01,dmax为2。对于ROUNDED B-02,dmax为6。

请注意,错误的不仅是显示的示例。在问题的第一个示例中,ROUNDED从不进行操作,并且始终删除一个有效的小数,因此,只有在四舍五入前的答案为十分之一时,您才获得正确的答案。然后,这些正确答案被九个另外的答案掩盖,这些其他答案由于截断而变得相同。

如果您始终编写有效的COMPUTE,就不会遇到问题。 ROUNDED仅对最终结果起作用。如果您需要任何中间字段,请分别计算并在新的计算中使用该结果。

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

关于ibm-midrange - AS/400:使用COMPUTE函数时,不同字段定义的结果不一致,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14272981/

相关文章:

cobol - COBOL 中的嵌套执行循环?

loops - 如何根据输入控制循环? (为什么这个循环永远?)

binary - 在 COBOL 中与 Pic X 数据执行二进制 OR

在 COBOL 中搜索和搜索所有内容

sql - 为什么我会收到 "[SQL0802] Data conversion of data mapping error"异常?

ibm-midrange - 在rpg中使用激活组的真正优势是什么

cobol - 除法功能是什么意思

vb6 - 将 AS400 (IBM i) 配置文件 token 传递到 OLE DB 连接

sql - 在带有 PK 标识列的表中插入期间出现 AS400 DB2 重复键错误