【问题标题】:How to convert data to packed decimal format如何将数据转换为压缩十进制格式
【发布时间】:2019-06-11 14:26:35
【问题描述】:

我正在尝试将浮点数转换为压缩十进制,但我找到的最接近的解决方案是 Gilbert Le Blanc 来自这篇文章: Java: Convert String to packed decimal

这个解决方案被复制粘贴了数百遍,整个堆栈溢出,但它存在严重缺陷:

public class PackedDecimal {

    public static byte[] format(long number, int bytes) {
        byte[] b = new byte[bytes];

        final byte minusSign = 0x0D; // Minus
        final byte noSign = 0x0F; // Unsigned

        String s = Long.toString(number);
        int length = s.length();
        boolean isNegative = false;

        if (s.charAt(0) == '-') {
            isNegative = true;
            s = s.substring(1);
            length--;
        }

        int extraBytes = length - bytes + 1;

        if (extraBytes < 0) {
            // Pad extra byte positions with zero
            for (int i = 0; i < -extraBytes; i++) {
                b[i] = 0x00;
            }
        } else if (extraBytes > 0) {
            // Truncate the high order digits of the number to fit
            s = s.substring(extraBytes);
            length -= extraBytes;
            extraBytes = 0;
        }

        // Translate the string digits into bytes
        for (int i = 0; i < length; i++) {
            String digit = s.substring(i, i + 1);
            b[i - extraBytes] = Byte.valueOf(digit);
        }

        // Add the sign byte
        if (isNegative) {
            b[bytes - 1] = minusSign;
        } else {
            b[bytes - 1] = noSign;
        }

        return b;
    }

    public static void main(String[] args) {
        long number = -456L;
        byte[] b = PackedDecimal.format(number, 5);
        System.out.println("Number: " + number + ", packed: " + byteToString(b));

        number = 0L;
        b = PackedDecimal.format(number, 5);
        System.out.println("Number: " + number + ", packed: " + byteToString(b));

        number = 5823L;
        b = PackedDecimal.format(number, 5);
        System.out.println("Number: " + number + ", packed: " + byteToString(b));

        number = 123456L;
        b = PackedDecimal.format(number, 5);
        System.out.println("Number: " + number + ", packed: " + byteToString(b));
    }

    public static String byteToString(byte[] b) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < b.length; i++) {
            sb.append("0x");
            sb.append(Integer.toHexString((int) b[i]).toUpperCase());
            sb.append(" ");
        }
        return sb.toString();
    }

}

这是测试结果。

Number: -456, packed: 0x0 0x4 0x5 0x6 0xD 
Number: 0, packed: 0x0 0x0 0x0 0x0 0xF 
Number: 5823, packed: 0x5 0x8 0x2 0x3 0xF 
Number: 123456, packed: 0x3 0x4 0x5 0x6 0xF 

这段代码的问题是:

  1. 它只处理int。 double 和 big decimal 也可以转换为压缩十进制。
  2. 每个数字由半个字节表示,因此压缩十进制中的位数必须始终是偶数而不是奇数。
  3. 据我所知,在 COBOL 运行应用程序中,通常每个转换的数据字段都有一个长度变量,而 小数点后的数字。对于每个压缩十进制数,代码的固定长度为 5。

压缩十进制中使用的半字节数计算为 length + 1 +(如果半字节总数为奇数则为 1)

这段代码忽略了所有这些。

以下是压缩十进制转换(l=length, half of bytes used)(p=number of half of bytes used after decimal point)的一些示例:

(l=4)(p=0) +123 > 00123C (l=4)(p=0)-123 > 00123D 
(l=4)(p=0)(Unsigned) 12345 > 12345F 
(l=6)(p=2)(Unsigned) 12345.67 > 1234567F
(l=8)(p=2)(Unsigned) 12345.67 > 001234567F 
(l=6)(p=3)(Unsigned) > 12345.67 > 2345670F

有什么改进的建议吗?

【问题讨论】:

    标签: java type-conversion format byte dataformat


    【解决方案1】:

    有这方面的库。例如。您可以使用 IBM 的 JTOpen 来实现 AS400 兼容性。 blog post by Michael Wan 中描述了它用于将 Java BigDecimal 转换为压缩十进制并返回的用法 - 引用:

    /**
     * Java BigDecimal to Packed Decimal
     */
    //15 means total number of digits, 5 means number of decimal places
    AS400PackedDecimal packedDecimal = new AS400PackedDecimal(15, 5);
    BigDecimal javaBigDecimal = new BigDecimal("1000.12345");
    byte[] convertedBytesArray = packedDecimal.toBytes(javaBigDecimal);
    
    /**
     * Packed Decimal to Java Big Decimal
     */
    BigDecimal convertedBigDecimal = (BigDecimal)packedDecimal.toObject(convertedBytesArray);
    

    其他我不知道的库:

    【讨论】:

      【解决方案2】:

      我用谷歌搜索了一下,发现了这个:https://docs.oracle.com/cd/E18150_01/javadocs/CICS/com/stc/eways/cics/PackedDecimal.html

      PackedDecimal 类确实有一个方法toPackedDecimal,它接受一个数字,因此接受一个Float

      【讨论】:

        【解决方案3】:

        有一个选项可以使用位操作将数字打包为 COMP3 (COBOL) 格式。以下代码 sn-p 仅适用于大型机 COMP3 格式打包

        每个数字都以 8 位存储在最新的系统中,但 COMP3 包含 2 位数字。 例如,

        1) 123 - 将存储在 2 个字节中 - 123 将被视为 +123 - 所以存储在 2 个字节中

        2) 1234 - 将存储在 3 个字节中 - 123 将被视为 +1234 - 因此存储在 3 个字节中,最左边的 4 位将为零

        3) -123 - 将存储在 2 个字节中 - 所以存储在 2 个字节中

            byte[] packed = new byte[(data.length() - startAt) / 2 + 1];
            int inIdx = chars.length - 1;
            int outIdx = packed.length - 1;
        
            int temp = (chars[(inIdx--)] & 0xF) << 4;
            digit |= temp;
            packed[(outIdx--)] = (byte)(digit & 0xFF);
        
            for (; outIdx >= 0; --outIdx) {
              if (inIdx < 0)
                break;
              if ((chars[inIdx] < 48) || (chars[inIdx] > 57))
              {
                logger.createErr("Invalid numeric character at " + inIdx);
                return null;
              }
        
              digit = chars[(inIdx--)] & 0xF;
              if (inIdx >= 0) {
                temp = (chars[(inIdx--)] & 0xF) << 4;
                digit |= temp;
              }
              packed[outIdx] = (byte)digit;
            }
            return packed;
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2022-03-18
          • 2020-01-04
          • 2016-03-23
          • 1970-01-01
          • 2010-10-15
          • 1970-01-01
          • 2015-03-17
          相关资源
          最近更新 更多