- 为什么您的代码没有产生您期望的输出
这只是我的猜测,因为在我的计算机上它不是那样工作的。
当您将MOVE 从WS-ALPHANUMERIC 转换为WS-HEX 时,字符串'86' 转换为十进制数86。
但是 WS-HEX 只有一个字节长并且采用 COMP-3 格式。这种格式只能存储一位十进制数字和符号。
我猜在您的环境中,当您将比容量更大的数字移动到 COMP-3 时,它会采用它可以容纳的最大十六进制值:0xF。
在我的环境中,它只需要数字 86 的数字 6。
因此,当您显示时,它会转换为使用情况显示,因此您的第一个 0xF 用于使用格式,然后您的 0xF 用于“溢出”我猜。
在我的电脑上你只会得到一个 0xF6。
- 产生预期输出的解决方案
免责声明:我原本以为您的输入只能是小数,例如“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(一个半字节,即十六进制数字的大小),将它们放置在正确的位置。
- 接受完整的十六进制输入范围(内存密集型)的解决方案
代码如下:
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 效率。
该解决方案的基本思想是哈希表。这个解决方案只不过是一个非常原始的哈希表,其中哈希函数是恒等函数(一个非常非常糟糕的哈希函数)。
- 另一种接受完整十六进制输入范围(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 的)。我们只需要找到匹配的字符,然后匹配字符的索引等于十六进制的值。
- 结论
有几种方法可以做你想做的事。基本思想是:
- 实现一种将字符转换为其十六进制值的方法
- 遍历输入字符串的所有字符并使用它们的位置来赋予它们正确的权重。
您的解决方案将始终在内存效率和时间效率之间进行权衡。有时你想保留你的记忆,有时你希望执行得非常快。有时你想找到一个中间立场。
要朝这个方向发展,我们可以在内存方面改进第 3 项的解决方案,但会牺牲 cpu。这将是第 3 项和第 4 项之间的折衷方案。
为此,我们可以使用模运算来限制存储可能性的数量。这样做意味着实现一个真正的哈希表。