大型机 COBOL COMPUTE T​​RUNC 查询

Mainframe COBOL COMPUTE TRUNC Query

我想知道为什么这两种情况的结果不同。

工作存储:

WS-SUM-LEN PIC S9(4) COMP. 
WS-LEN-9000   PIC 9(5) VALUE 9000.
WS-TMP-LEN    PIC 9(5).
WS-FIELD-A    PIC X(2000).

案例 1) COMPUTE WS-SUM-LEN = WS-LEN-9000 + LENGTH OF WS-FIELD-A

结果:WS-SUM-LEN = 1000

案例 2)

MOVE LENGTH OF WS-FIELD-A TO WS-TMP-LEN
COMPUTE WS-SUM-LEN = WS-LEN-9000 + WS-TMP-LEN

结果:WS-SUM-LEN = 11000

编译选项为TRUNC(OPT)。为什么情况 2 没有发生 trunc?

来自公开文档:

TRUNC(OPT) is a performance option. When TRUNC(OPT) is in effect, the compiler assumes that data conforms to PICTURE specifications in USAGE BINARY receiving fields in MOVE statements and arithmetic expressions. The results are manipulated in the most optimal way, either truncating to the number of digits in the PICTURE clause, or to the size of the binary field in storage (halfword, fullword, or doubleword). 

Tip: Use the TRUNC(OPT) option only if you are sure that the data being moved into the binary areas will not have a value with larger precision than that defined by the PICTURE clause for the binary item. Otherwise, unpredictable results could occur. This truncation is performed in the most efficient manner possible; therefore, the results are dependent on the particular code sequence generated. It is not possible to predict the truncation without seeing the code sequence generated for a particular statement. 

仔细阅读 "Tip",看看它对您的情况意味着什么。 (提示:这意味着问你做的问题没有意义,因为它字面意思是 "whatever happens, it was unpredictable" 或 iow "there is no explanation for what happens")。

要使编译器行为可预测,请切换到 TRUNC(BIN) 或 TRUNC(STD)。 STD 有利于标准合规性,但不利于 CPU 用法,BIN 有利于 CPU 用法,但需要您多加小心(因为根本不会发生小数截断)。

IBM 企业 COBOL 中的二进制字段

警告

编译器选项 TRUNC 决定如何生成二进制字段的代码。

不要只是启动并更改站点选项 TRUNC 的默认设置。 TRUNC 的不同设置会产生不同的结果。

从 TRUNC(BIN) 更改为 TRUNC(STD) 将为定义字段的 PICture 表示的 decimal-values 之外的任何值提供不同的结果。对于带符号的字段,同样适用于负值。

01  a-good-name              BINARY PIC 99.

    ADD 1                    TO a-good-name

使用 TRUNC(STD),一旦达到 99,结果将被处理 运行。使用 TRUNC(BIN),一旦达到 65535,结果将被 t运行cated(如果该字段已签名,则 t运行cation 将像以前一样为 99 TRUNC(STD)和 32767 (BIN)).

从 TRUNC(BIN) 到 TRUNC(OPT) 的更改,无需更改程序,仅当二进制字段的所有、完全所有使用限制为图片表示的 decimal-values 时才有可能。特定的代码片段可能看起来 "work",但如果所有二进制字段的使用在您的系统上的两个编译器选项之间给出相同的结果,那将是一个巨大的巧合。

从TRUNC(STD) 到TRUNC(OPT) 类似。虽然工作的巧合数量会减少,但这会增加一种虚假的安全感,从而有可能在一段时间内遗漏细微的差异。

可以毫不费力地从真正使用 TRUNC(OPT) 更改为 TRUNC(STD) 或 TRUNC(BIN)。但是,你为什么要这样做?

但是,如果你使用的不是正品(使用不符合PICture的数据的TRUNC(OPT)),那么你的原始结果是不可靠的,你会得到差异 如果更改为 TRUNC(STD) 并且更改为 TRUNC(BIN) 可能会有所不同。

简而言之,更改编译器选项 TRUNC 的 site-default 是需要非常仔细考虑的事情,并且必须包括对结果验证的规定。

站点 do 有时会进行这样的更改,我所知道的唯一更改是 TRUNC(BIN)(大部分)和 TRUNC(STD) 到 TRUNC(OPT),因为性能原因。这些都是作为项目完成的,而不仅仅是通过更改选项并从那里犯错误。

不要在系统 中覆盖 TRUNC 的 site-default。如果您的程序使用相同的二进制数据(来自文件、数据库、inter-program 通信、消息或任何其他方式)并且它们并不都以相同的方式处理数据,那就是自找麻烦.

一些迷思

文中后面会有进一步的解释

  1. There is a difference between TRUNC(BIN) and making all your binary fields COMP-5 (or COMPUTATIONAL-5).

没有任何区别。指定 TRUNC(BIN) 时,编译器会将所有二进制字段视为 COMP-5。

  1. Native-binary is faster than COBOL binary (a binary field with decimal limits defined by the PICture clause).

虽然这个术语本身让很多有经验的人认为它会更快("it'll be like when I code it myself in Assembler"),但实际上它总体上更慢。 slowing-down 随着 field-size 的增加而增加。

  1. Native-binary (COMP-5/COMPUTATIONAL-5) does not truncate.

确实如此。它 运行 对应 field-size。因为它t运行归类到field-size,所以中间字段必须总是大于源字段,这意味着必须使用更多的指令,并且不同的指令。

另外,重要的是要知道,ON SIZE ERROR 子句(可以与所有算术动词一起使用)总是只使用 PICture 子句来确定 size-error 已经发生。也就是说,如果您有一个 COMP-5 PIC S9(4),它可以包含最大正值 32,767,然后执行以下操作:

MULTIPLY that-field BY 10 GIVING that-field
  ON SIZE ERROR
      DISPLAY "Busted"
END-MULTIPLY

任何高于 9999 的值都会导致处理 DISPLAY。

这实际上意味着 "don't use ON SIZE ERROR with COMP-5 or TRUNC(BIN)"。

  1. TRUNC(OPT) generates optimal code.

单独来看,确实如此。但是,这并不排除在更广泛的上下文中对编译器选项 OPTIMIZE/OPT 进行进一步优化。

  1. When using binary fields, always use the maximum PICture for the size of the field

一个1-4位的二进制字段会占用half-word两个字节的存储空间。具有 5-9 位数字、一个字或四个字节的全字。 10-18 位数字,一个 double-word 八个字节。

老年人的建议是始终指定四位数字、九位数字和 18 位数字(好吧,no-one 真的超过九位,是吗...?)。

这是我过去收到的建议,也是我自己给出的建议。但是,在 Enterprise COBOL 中,这不是一个好建议。

此处最好的建议是定义所需的位数。这有时会提高性能,永远不会降低性能,并且会通过最好地描述数据使程序更容易理解。

  1. When using binary fields, always make them signed.

我过去收到和给出的建议更多。与企业 COBOL 不同。如果字段可以包含负值,请将其签名。否则使其无符号。

有时,对于接口,一个字段是否应该被签名并不明确。但是,从预期的最大值中可以看出。与字段定义一样用法)。

例如,SQL VARCHAR 作为 host-variable 的最大大小为 32767 字节。由于实际长度保存在 two-byte 二进制字段中,因此应对该字段进行签名。任何值 "above" 32767 都会被 DB2/SQL.

误解
  1. Since nine decimal digits can fully fit within a word/fullword, there is no problem using nine decimal digits for a COMP/COMP-4/BINARY definition (without TRUNC(BIN)).

因为编译器必须处理十进制的 t运行cation,并且因为任何可能导致 t运行cation 的东西都需要 "next size up",一个九的二进制字段数字可能需要 double-word 中间字段。因此需要代码转换为 double-word,并将结果从 double-word 转换回单词。如果需要九位数字,通常定义 10 位数字会更好并节省转换。

备注

以上内容均适用于 Enterprise COBOL V4.2。

IBM 完全重写了 code-generation 和优化(现在有两个可能的优化级别)For Enterprise COBOL V5。二进制字段的处理有相当大的改进,包括,例如,一旦知道 t运行cation 是必要的,就只对值进行 t运行cation。除了性能差异的规模之外,我不知道 V5 的使用在这里改变了什么。与早期版本的 Enterprise COBOL 相比,V5 对二进制字段的所有一般用法都应该更快。

二进制字段

COBOL,对于二进制字段,使用由图片大小决定的十进制最大值。

这样一个PIC为9的字段在t运行cation之前可以包含最大值9。如果有符号,值的范围是 -9 到 +9。超出该范围的值将被处理 运行。

对于 PIC 99、99,如果有符号 -99 到 99。

对于 PIC 999、999,如果有符号 -999 到 999。

你明白了……想法。

这些值的存储方式取决于 compiler-implementation。

事实上,根据标准,COBOL 直到最近 (1985) 才支持二进制字段 (USAGE BINARY)。支持哪些实际 "non-display" 字段以及如何支持 USAGE COMPUTATIONAL,其具体细节为 compiler-dependent.

通常跨编译器 COMP、COMP-1 和 COMP-2(二进制,带十进制最大值,短 floating-point 和长 floating-point)是标准的,但不是标准的一部分。除了 COMP-2,字段定义的含义可能因编译器而异。

因此,第一个建议,建议您的本地站点标准使用 BINARY 而不是 COMP 用于新代码(并且 PACKED-DECIMAL 而不是 COMP-3,用于 packed-decimal 字段)。 Enterprise COBOL 中的 BINARY(和 COMP-4)只是 COMP 的别名,所以这样做绝对没有问题。

还有另一种二进制字段,即native-binary字段。在企业 COBOL 中,这是 USAGE COMP-5。

COMP-5 的 field-size 由 PICture 定义决定,但它的最大值是字段大小可能的完整 bit-pattern。 PIC S9(4) COMP-5 可以包含 -32768 到 32767.

请注意,此时有一个 native-binary 字段,这可能看起来 counter-intuitive,通常需要更多生成的 machine-code 来支持其使用。这是因为它 t运行 属于 field-size,而不是 PICture。

另请注意,有一个地方不会发生这种情况,即 ON SIZE ERROR,如果值超过 PICture 大小,则为真。这意味着,在我看来,不要将 ON SIZE ERROR 与 COMP-5(或 TRUNC(BIN),稍后见)字段一起使用。

编译器选项 TRUNC

编译器选项 TRUNC 定义如何为二进制字段生成 machine-code。共有三个选项:

TRUNC(BIN)

T运行指向 field-size。

这会将程序 (COMP/COMP-4/BINARY) 中的所有非 native-binary 字段视为 native-binary(就好像它们已被定义为 COMP-5)。

这允许使用所有位模式,但会影响性能。

截断(标准)

T运行图片大小。

为 COBOL 标准 t运行 生成 machine-code 图片大小。 PIC 9(n) 最多可包含 n 个有效数字,当字段为 "target"(字段值更改)时,它们将被 t运行 分类。

截断(选择)

T运行任何类型的阳离子仅在方便时才使用。

我将其描述为编码器和编译器之间的契约。编码器约定从不(如从不)允许值超过 PICture 大小。编译器约定在这种情况下始终正确处理。

如果编码员违反合同,编码员完全应该为随后的垃圾负责。

何时使用 TRUNC 的每个设置(进一步推荐)

BIN从来没有。将 COMP-5 用于需要访问所有位的各个字段(注意 SQL 和 CICS "system" 字段,以及来自 non-Mainframe 源的外部数据,以及 inter-language 通信在 COBOL 和 JAVA/C/C++ 之间在其他任何地方,字段的 data-maxima 超出了 PICture 并且不可能使字段变大(因为字段大小的实际逻辑定义在您的程序之外)。

STD 使用此选项,除非您的所有数据一如既往地始终符合 PICture。

OPT 仅使用此,如仅,如果所有,如所有,您的数据始终如一,符合 PICture。

例如,如果您有 COMP PIC 99,则在使用 OPT 时,您不得允许其值为 99,然后再将其加一。或类似的东西

答案

您使用了TRUNC(OPT),签订了合同。你立即违约了。都是你的错。

警告

如果您的站点正在使用 TRUNC(OPT) 而不是每个人都完全了解其含义,那么您将会遇到问题。

上述神话的证实

  1. There is a difference between TRUNC(BIN) and making all your binary fields COMP-5 (or COMPUTATIONAL-5).

在小程序中定义两个字段。它们应定义为 COMP/COMP-4/BINARY(或 COMPUTATIONAL/COMPUTATIONAL-4,如果您愿意的话)。

在程序中,向每个字段添加文字(使用两个单独的语句执行此操作,以便更容易理解,除非您对列表中的生成代码有经验)。

使用编译器选项 LIST、NOOFFSET 编译程序(这将在编译器列表中生成以 so-called "pseudo-assembler" 格式显示生成的 machine-code 的输出)和 TRUNC( BIN).

复制程序。在文案中,将两个字段的USAGE改为COMP-5(或COMPUTATIONAL-5)。

再次使用 LIST,NOOFFSET 编译此程序,但这次 TRUNC 的值无关紧要,因为它不影响 COMP-5 字段。

比较输出列表。差一个字节就吃别人的帽子

  1. Native-binary is faster than COBOL binary (a binary field with decimal limits defined by the PICture clause).

来自 IBM COBOL Cafe 的讨论:https://www.ibm.com/developerworks/community/forums/html/topic?id=ae9ef6bc-6e4e-43f8-a814-e66bea25fb8c&ps=25

这里是 PIC 9(3) 乘以 PIC 9(5)。

使用 TRUNC(STD)

000023  MULTIPLY                                                             
   000258  5820 8008               L     2,8(0,8)                PIC9-5      
   00025C  4C20 8000               MH    2,0(0,8)                PIC9-3      
   000260  5020 8010               ST    2,16(0,8) 

使用 TRUNC(BIN)

000019  MULTIPLY                                                              
   00023C  4820 8030               LH    2,48(0,8)               PICS9-4      
   000240  5840 8038               L     4,56(0,8)               PICS9-8      
   000244  8E40 0020               SRDA  4,32(0)                              
   000248  5D40 C000               D     4,0(0,12)               SYSLIT AT +0
   00024C  4E50 D120               CVD   5,288(0,13)             TS2=16       
   000250  F154 D110 D123          MVO   272(6,13),291(5,13)     TS2=0        
   000256  4E40 D120               CVD   4,288(0,13)             TS2=16       
   00025A  9110 D115               TM    277(13),X'10'           TS2=5        
   00025E  D204 D115 D123          MVC   277(5,13),291(13)       TS2=5        
   000264  4780 B05C               BC    8,92(0,11)              GN=10(00026C)
   000268  9601 D119               OI    281(13),X'01'           TS2=9        
   00026C                 GN=10    EQU   *                                    
   00026C  4E20 D120               CVD   2,288(0,13)             TS2=16       
   000270  FC82 D111 D125          MP    273(9,13),293(3,13)     TS2=1        
   000276  D202 D128 C008          MVC   296(3,13),8(12)         TS2=24       
   00027C  D204 D12B D115          MVC   299(5,13),277(13)       TS2=27       
   000282  4F20 D128               CVB   2,296(0,13)             TS2=24       
   000286  F144 D12B D110          MVO   299(5,13),272(5,13)     TS2=27       
   00028C  4F50 D128               CVB   5,296(0,13)             TS2=24       
   000290  5C40 C000               M     4,0(0,12)               SYSLIT AT +0
   000294  1E52                    ALR   5,2                                  
   000296  47C0 B08E               BC    12,142(0,11)            GN=11(00029E)
   00029A  5A40 C004               A     4,4(0,12)               SYSLIT AT +4
   00029E                 GN=11    EQU   *                                    
   00029E  1222                    LTR   2,2                                  
   0002A0  47B0 B098               BC    11,152(0,11)            GN=12(0002A8)
   0002A4  5B40 C004               S     4,4(0,12)               SYSLIT AT +4
   0002A8                 GN=12    EQU   *                                    
   0002A8  5050 8040               ST    5,64(0,8) 

不需要任何 IBM Assembler 知识就可以计算出这两段代码中的哪一段 运行 更快。

line-numbers(19 与 23)的区别在于 TRUNC(BIN) 使 PICture 大小无关紧要,因此我进行了三个计算,使用不同大小的字段执行相同的操作,对于 TRUNC(BIN),每个字段的代码都是相同的,因为每个字段的大小是相同的,一个 word/fullword 四个字节。

  1. Native-binary (COMP-5/COMPUTATIONAL-5) does not truncate.

见上面的代码。由于需要提供 t运行 阳离子,它是如此巨大。提供小数 t运行cation 的需要取决于 COBOL 标准,这是语言中必须发生的事情。

  1. TRUNC(OPT) generates optimal code.

生成的代码始终是最有效的 code-sequence。在优化之前,相同的 code-sequence 将始终生成相同的代码。

但是,优化器能够发现特定未受干扰的状态可用于程序中较早的 source-field,并用依赖于 source-field 的代码替换部分或全部 TRUNC(OPT) 代码=342=]值。

  1. When using binary fields, always use the maximum PICture for the size of the field

来自上面引用的同一 IBM COBOL Cafe 讨论,具有以下定义:

   01  PIC9-3                       BINARY PIC 999.
   01  PIC9-5                       BINARY PIC 9(5).
   01  THE-RESULT8                  BINARY PIC 9(8).

   01  PIC9-4                       BINARY PIC 9(4).
   01  PIC9-8                       BINARY PIC 9(8).
   01  THE-RESULT                   BINARY PIC 9(8).

这些计算:

       MULTIPLY PIC9-4              BY PIC9-8
         GIVING                     THE-RESULT
       MULTIPLY PIC9-3              BY PIC9-5
         GIVING                     THE-RESULT8

这是为 TRUNC(STD) 生成的代码:

000021  MULTIPLY                                                             
   000248  4830 8018               LH    3,24(0,8)               PIC9-4      
   00024C  5C20 8020               M     2,32(0,8)               PIC9-8      
   000250  5D20 C000               D     2,0(0,12)               SYSLIT AT +0
   000254  5020 8028               ST    2,40(0,8)               THE-RESULT  

000023  MULTIPLY                                                             
   000258  5820 8008               L     2,8(0,8)                PIC9-5      
   00025C  4C20 8000               MH    2,0(0,8)                PIC9-3      
   000260  5020 8010               ST    2,16(0,8) 

pseudo-assembler的第一个块是PICture中给出相同field-size的最大位数。一个BINARY PIC 9(3)占据一个half-word,而9(4)是最大的一个可以出现在half-word中。 PIC 9(5) 占用 word/fullword,并且,给定神话 7,为此使用八位数字(为了对这个特定的神话公平)。

第二块是准确表示数据的位数,在进行乘法时不需要t运行cation。

使用 "full-size" 图片 保证 总是会发生不必要的 t运行 阳离子。

指令数的差别很小,LH比L快,所以加到full-size上。但是ML慢很多,MHL慢但是比M快。所以再加上最佳尺寸。并且在第二个块中根本不需要D(一个除法,它很慢,很慢)(因为不需要t运行cation)。所以 bad-boy 到 full-size 字段。

optimal-size 字段的 TRUNC(OPT) 代码也更快,尽管两者之间的差异不是很大(因为 code-sequence 中的 TRUNC(OPT) 决定它确实如此不需要以 10 为基数的 t运行 阳离子,并且在一百万年内不会考虑将 t运行 阳离子转换为 field-size)。

  1. When using binary fields, always make them signed.

再次来自同一个 IBM COBOL Cafe 讨论,这里是 same-length 有符号字段与无符号字段,TRUNC(STD):

000019  MULTIPLY                                                             
   000238  4830 8030               LH    3,48(0,8)               PICS9-4     
   00023C  5C20 8038               M     2,56(0,8)               PICS9-8     
   000240  5D20 C000               D     2,0(0,12)               SYSLIT AT +0
   000244  5020 8040               ST    2,64(0,8)               THE-RESULTS

000021  MULTIPLY                                                             
   000248  4830 8018               LH    3,24(0,8)               PIC9-4      
   00024C  5C20 8020               M     2,32(0,8)               PIC9-8      
   000250  5D20 C000               D     2,0(0,12)               SYSLIT AT +0
   000254  5020 8028               ST    2,40(0,8)

同时使用TRUNC(OPT)和TRUNC(BIN)编译时,代码与上面不同,但是这两种情况下的每个 code-sequence 在这些选项中都是相同的。

符号的存在与否对生成的代码没有影响。

除了一种情况。神话 7 发挥作用的地方。对于 nine-digit 二进制文件,使用有符号字段与无符号字段确实生成的代码更少,但生成的代码比使用八位数字时生成的代码更多。

  1. Since nine decimal digits can fully fit within a word/fullword, there is no problem using nine decimal digits for a COMP/COMP-4/BINARY definition (without TRUNC(BIN)).

摘自 IBM Enterprise COBOL 版本 4 第 2 版性能调整 论文,第 32-33 页:

The following shows the general performance considerations (from most efficient to least efficient) for the number of digits of precision for signed binary data items (using PICTURE S9(n) COMP) using TRUNC(OPT):

n is from 1 to 8

for n from 1 to 4, arithmetic is done in halfword instructions where possible for n from 5 to 8, arithmetic is done in fullword instructions where possible

n is from 10 to 17 arithmetic is done in doubleword format

n is 9

fullword values are converted to doubleword format and then doubleword arithmetic is used (this is SLOWER than any of the above)

n is 18 doubleword values are converted to a higher precision format and then arithmetic is done using this higher precision (this is the SLOWEST of all for binary data items)

TRUNC(STD) 也有类似的问题。 TRUNC(BIN) 已经具有 built-in 数字 1-9 的慢度,因此不会进一步受到影响。