【问题标题】:convert alphanumeric PIC X(02) to hex value 9(01) COMP-3 in cobol将字母数字 PIC X(02) 转换为 cobol 中的十六进制值 9(01) COMP-3
【发布时间】:2021-12-21 04:57:40
【问题描述】:

我有字母数字值 = '86',其长度定义为 PIC x(02)。我需要将其转换为十六进制 x'86',其长度定义为 PIC 9(01) comp-3。

示例:

01 WS-ALPHANUMERIC PIC X(02) VALUE '86'.   
01 WS-HEX          PIC 9(01) COMP-3.

PROCEDURE DIVISION.

MOVE WS-ALPHANUMERIC   TO WS-HEX.

DISPLAY WS-HEX.

STOP RUN

我的线轴中有 x'FF'。但我期待 x'86'。

【问题讨论】:

标签: cobol


【解决方案1】:
  1. 为什么您的代码没有产生您期望的输出

这只是我的猜测,因为在我的计算机上它不是那样工作的。

当您将MOVE 从WS-ALPHANUMERIC 转换为WS-HEX 时,字符串'86' 转换为十进制数86。

但是 WS-HEX 只有一个字节长并且采用 COMP-3 格式。这种格式只能存储一位十进制数字和符号。 我猜在您的环境中,当您将比容量更大的数字移动到 COMP-3 时,它会采用它可以容纳的最大十六进制值:0xF。 在我的环境中,它只需要数字 86 的数字 6。

因此,当您显示时,它会转换为使用情况显示,因此您的第一个 0xF 用于使用格式,然后您的 0xF 用于“溢出”我猜。

在我的电脑上你只会得到一个 0xF6。

  1. 产生预期输出的解决方案

免责声明:我原本以为您的输入只能是小数,例如“87596”、“12”或“88”。此解决方案不适用于像“F1”或“99F”这样的十六进制输入。通过改进这个,我在下面的第 3 和第 4 项中构建了更完整的解决方案

如果您的系统是 64 位,我建议的解决方案在输入字符串中最多可以占用 16 位数字,因为存储一个十六进制数字需要 4 位。

因此,如果您想要更大的输入,则必须使用多个结果变量。

如果您只想将它​​放在一个字节中,您只需将Result 设为PIC 9(1) 而不是PIC 9(18)

IDENTIFICATION DIVISION.
PROGRAM-ID. CNVRSN.

ENVIRONMENT DIVISION.

DATA DIVISION.
WORKING-STORAGE SECTION.

      01  RawInput PIC X(02) VALUE '86'.

      01  FormattedInput PIC 9(16).
      01  FractionedInput REDEFINES FormattedInput
         05 Digit PIC 9 OCCURS 16.          
      01  Shifting PIC 9(18) COMP-5 VALUE 1. 
      01  I PIC 99 COMP-5.

      01  Result PIC 9(18) COMP-5 VALUE 0.
      01  DisplayResult REDEFINES Result PIC X(8).
     


PROCEDURE DIVISION.

       MOVE RawInput TO FormattedInput.
  
       PERFORM VARYING I FROM LENGTH OF FractionedInput
                    BY -1 UNTIL I < 1
  
        COMPUTE Result = Result + Digit(I)*Shifting
        MULTIPLY 16 BY Shifting
  
       END-PERFORM
  
       DISPLAY 'DisplayResult : ' DisplayResult
       .
END PROGRAM CNVRSN.

代码的工作原理是将字符串转换为多个USAGE DISPLAY,第一步是 MOVE RawInput to FormattedInput.

我们使用的事实是,每个数字与只有一位数字的数字具有相同的格式 (PIC 9)。这允许我们用REDEFINES 的FomattedInput inFractionedInput 分割数组元素中的数字

如您所见,我从头到尾遍历数组,因为最低有效字节位于数组的末尾(内存中的最高地址),而不是开头(内存中的最低地址)。

然后我们根据需要将每个十六进制数字向左移动 2^4(一个半字节,即十六进制数字的大小),将它们放置在正确的位置。

  1. 接受完整的十六进制输入范围(内存密集型)的解决方案

代码如下:

IDENTIFICATION DIVISION.
PROGRAM-ID. CNVRSN.

ENVIRONMENT DIVISION.

DATA DIVISION.
WORKING-STORAGE SECTION.

  01  RawInput PIC X(02) VALUE '86'.

  01  FormattedInput PIC X(16).
  01  FractionedInput REDEFINES FormattedInput
     05 Digit PIC X OCCURS 16.          
  01  I PIC 99 COMP-5.
  
  01  ConversionTableInitializer. 
    05 FILLER PIC X(192).
    05 TenToFifteen PIC X(06) VALUE X'0A0B0C0D0E0F'.
    05 FILLER PIC X(41).
    05 ZeroToNine PIC X(10) VALUE X'00010203040506070809'.

  01  ConversionTable Redefines ConversionTableInitializer. 
    05 DigitConverter PIC 99 COMP-5 OCCURS 249.

  01  Result PIC 9(18) COMP-5 VALUE 0.
  01  DisplayResult REDEFINES Result PIC X(8).
 

PROCEDURE DIVISION.
   MOVE RawInput TO FormattedInput.

   PERFORM VARYING I FROM 1 BY 1 
                     UNTIL I > LENGTH OF FractionedInput
                        OR Digit(I) = SPACE


    COMPUTE Result = Result*16 + DigitConverter(Digit(I))

   END-PERFORM

   DISPLAY 'DisplayResult : ' DisplayResult
   .
END PROGRAM CNVRSN.

此解决方案的想法是将每个字符 (0,1...,E,F) 转换为其十六进制值。为此,我们将它们的编码值作为字符串(例如 A 的 0xC1 = 0d193)作为数组的索引。

这非常浪费内存,因为我们分配了 249 个字节来仅存储 16 个半字节的信息。然而,访问数组元素是一项非常快速的操作:我们正在用内存使用来换取 CPU 效率。 该解决方案的基本思想是哈希表。这个解决方案只不过是一个非常原始的哈希表,其中哈希函数是恒等函数(一个非常非常糟糕的哈希函数)。

  1. 另一种接受完整十六进制输入范围(CPU 密集型)的解决方案

免责声明:此解决方案由 @Jim Castro 在 cmets 中提出。

IDENTIFICATION DIVISION. 
PROGRAM-ID. CNVRSN.

ENVIRONMENT DIVISION.

DATA DIVISION.
WORKING-STORAGE SECTION.

  01  RawInput PIC X(02) VALUE '86'.

  01  FormattedInput PIC X(16).
  01  FractionedInput REDEFINES FormattedInput
     05 Digit PIC 9 OCCURS 16.          
  01  ConversionString PIC X(16) VALUE '0123456789ABCDEF'.
  01  ConversionTable REDEFINES ConversionString.
     05 ConversionEntry OCCURS 16 INDEXED BY Idx.                          
       10 HexDigit PIC X.   

  01  I PIC 99 COMP-5.
  


  01  Result PIC 9(18) COMP-5 VALUE 0.
  01  DisplayResult REDEFINES Result PIC X(8).
 


PROCEDURE DIVISION.

   MOVE RawInput TO FormattedInput.

   PERFORM VARYING I FROM 1 BY 1 
                     UNTIL I > LENGTH OF FractionedInput
                        OR Digit(I) = SPACE


    SET Idx To 1
    SEARCH ConversionEntry
      WHEN HexDigit(Idx) = Digit(I)
         COMPUTE Result = Result*16 + Idx - 1            
    END-SEARCH
    

   END-PERFORM

   DISPLAY 'DisplayResult : ' DisplayResult
   .
 END PROGRAM CNVRSN.

这里的想法仍然是将字符串数字转换为其值。然而,我们没有以内存效率换取 CPU 效率,而是相反。

我们有一个 ConversionTable,其中每个字符串都位于传达它们应该传达的值 + 1 的索引处(因为在 COBOL 数组中是基于 0 的)。我们只需要找到匹配的字符,然后匹配字符的索引等于十六进制的值。

  1. 结论

有几种方法可以做你想做的事。基本思想是:

  1. 实现一种将字符转换为其十六进制值的方法
  2. 遍历输入字符串的所有字符并使用它们的位置来赋予它们正确的权重。

您的解决方案将始终在内存效率和时间效率之间进行权衡。有时你想保留你的记忆,有时你希望执行得非常快。有时你想找到一个中间立场。

要朝这个方向发展,我们可以在内存方面改进第 3 项的解决方案,但会牺牲 cpu。这将是第 3 项和第 4 项之间的折衷方案。 为此,我们可以使用模运算来限制存储可能性的数量。这样做意味着实现一个真正的哈希表。

【讨论】:

  • 输入的有效范围是 '00' 到 'FF'。尝试将“F”乘以 16。你会得到什么?
  • @Jim Castro 啊,我的错!据我了解,我认为输入只能是十进制数字!我将精确编辑,这仅适用于输入字符串中的小数位。如果我在圣日找到一些时间,我会提出另一个解决方案
  • 您正朝着正确的方向前进,但您需要将十六进制字符转换为数字。尝试使用 01 HEXVALS PIC X(16) VALUE '0123456789ABCDEF' 并乘以匹配文字的索引。
  • 是的,我知道该怎么做,就像之前说的那样,我误解了有效的输入范围,所以我提出了一个不尝试与其他输入一起工作的解决方案。当我有时间时,我会调整它(现在不是这样)。如果你认为我应该删除知道,我可以
【解决方案2】:

我无权访问 IBM 大型机来测试此代码。

当我在在线 GnuCOBOL v2.2 编译器上运行代码时,我被 ASCII 而不是 EBCDIC 卡住了。

我已经发布了代码。这是你必须做的。

  • 确保顶部字节输出为 8,底部字节输出为 6。您正在将 EBCDIC 值转换为整数值。值 A - F hex 将具有与值 0 - 9 不同的 EBCDIC 值。
  • 确保乘法和加法正确

这是代码。您必须修复它才能使用 EBCDIC。

IDENTIFICATION DIVISION.
PROGRAM-ID. CONVERSION.

DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-ALPHANUMERIC              PIC X(02) VALUE '86'.

01 WS-WORK-FIELDS.
   05 WS-INPUT.
      10 WS-ONE. 
         15 WS-TOP-BYTE         PIC 99 COMP.
      10 WS-TWO.
         15 WS-BOTTOM-BYTE      PIC 99 COMP.
   05 WS-ACCUMULATOR            PIC S9(4) COMP.
   05 FILLER                    REDEFINES WS-ACCUMULATOR.
      10 FILLER                 PIC X.
      10 WS-HEX                 PIC X.

PROCEDURE DIVISION.
0000-BEGIN.
    MOVE WS-ALPHANUMERIC TO WS-INPUT
    DISPLAY WS-INPUT

    COMPUTE WS-TOP-BYTE = WS-TOP-BYTE - 183
    COMPUTE WS-BOTTOM-BYTE = WS-BOTTOM-BYTE - 183

    IF WS-TOP-BYTE NOT LESS THAN 16
        COMPUTE WS-TOP-BYTE = WS-TOP-BYTE - 57
    END-IF   

    IF WS-BOTTOM-BYTE NOT LESS THAN 16
        COMPUTE WS-BOTTOM-BYTE = WS-BOTTOM-BYTE - 57
    END-IF  
    
    DISPLAY WS-TOP-BYTE
    DISPLAY WS-BOTTOM-BYTE

    MOVE WS-TOP-BYTE TO WS-ACCUMULATOR
    MULTIPLY 16 BY WS-ACUMULATOR
    ADD WS-BOTTOM-BYTE TO WS-ACCUMULATOR

    DISPLAY WS-ACCUMULATOR
    DISPLAY WS-HEX

    GOBACK.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-05-06
    • 1970-01-01
    • 2013-09-12
    • 1970-01-01
    • 2018-01-22
    • 2016-09-04
    • 2017-06-17
    相关资源
    最近更新 更多