Ibm midrange AS/400:使用计算函数,结果不一致,字段定义不同

Ibm midrange AS/400:使用计算函数,结果不一致,字段定义不同,ibm-midrange,cobol,Ibm Midrange,Cobol,在使用AS/400中的计算函数时,我遇到了一个神秘的问题 情况如下: 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)

在使用AS/400中的计算函数时,我遇到了一个神秘的问题

情况如下:

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

计算机的格式很差。当乘以100时,尽可能早地做,因为如果你最后一次做,小数点后两位将消失(当除以100时,最后一次做,这样你就不会在早期丢失有效数字)

它不仅适用于100,所以想想看。先乘后除,不管涉及什么值。完全没有必要使用小数点后五位的字段来获得“正确”答案,除非您要求在最终答案中保留小数点后五位

COMPUTE WSAA-RESULT ROUNDED = 
                  (WSAA-AMOUNT-A / ( WSAA-AMOUNT-B-01 + WSAA-AMOUNT-C) * 100 )
计算机不是计算器或电子表格。它根据您的要求使用中间结果,而不是为任何内容提供大量小数位数的其他结果。使用所用字段中的小数位数要求小数精度

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

COMPUTE WSAA-RESULT ROUNDED = 
                  (WSAA-AMOUNT-A / ( WSAA-AMOUNT-B-01 + WSAA-AMOUNT-C) * 100 )
显示WSAA-RESULT。获取答案14.90(十四点九零)

显示WSAA-RESULT。通过删除四舍五入的值,获取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.9999N(六位小数,我不打算再做计算了,所以我把第六位保留为“n”)

为什么小数点后有三位、两位和六位?这六位是因为B-02(有五位,加上一位四舍五入,将所需的小数位数增加一位,以便可以计算四舍五入),两位是因为B-01(有两位小数),三位是因为B-01而四舍五入

这是一个重新工作的计算机,分为三个版本:

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

这是企业Cobol。OpenCobol似乎使用了不同的中间结果,这些结果可能是有文档记录的

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

“要了解有关中间结果的信息,您需要了解以下术语。 ... d中间结果的小数位数。(如果使用四舍五入短语,必要时可多加一位小数以确保准确性。) dmax在特定报表中,指以下各项中最大的一项: v最终结果字段所需的小数位数 v为任何操作数定义的最大小数位数, 除数或指数除外 v任何函数操作数的外部dmax“

在“错误”的例子中,加法得到两位小数(d1和d2都是加法的两位),除法得到三位小数(dmax是三位),乘法得到三位(二加零加一表示四舍五入)。尝试四舍五入后的最终答案(由于乘以100,两个低阶小数始终为零,因此它永远不会运行)被截断为两位小数

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

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

如果你总是写有效的计算,你就不会遇到问题。四舍五入仅对最终结果起作用。如果需要取整任何中间字段,请单独计算,并在新计算中使用结果


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

事实上,OpenCobol 1.1的结果与预期的一样:+000000000000015.00+000000000000015.00奇怪……我在Z/OS上得到了相同的结果——与中间结果有关?这是旧的(OPM)COBOL/400还是ILE COBOL编译器?问题在于,不是企业COBOL,也不是OpenCobol。“ibm midrange”标记表明了这一点。@warrent只要使用的COBOL版本符合ISO/ANSII标准(据我所知,所有ibm COBOL编译器都符合Arithement C),它们就应该产生相同的结果,因为管理中间结果的规则是在该标准中定义的。另一方面,开放式COBOL基本上是从COBOL到C的语言翻译器,并不完全符合标准,因此正如一位评论者所观察到的,没有给出相同的结果。warrent,本主题中的as/400也表明了这一点。那么呢?亲爱的各位,很抱歉延迟回复。我真诚地感谢你为抚慰我心中的问题所做的一切努力。我已经按照比尔的建议重新测试过了,结果看起来不错。很抱歉,我是cobol编码的初学者,对使用函数的实践不够敏感,并且不了解
"Operation ... Decimal places
+ or - ... d1 or d2, whichever is greater
* ... d1 + d2
/ ... (d2 - d1) or dmax, whichever is greater"