嵌入式二进制编码十进制数学 Java

Binary Coded Decimal Maths in embedded Java

我想使用字节数组(BCD 格式)表示的小数以字节数组的形式对小数值进行数学增量。

一个例子是我想在数学中做 255 + 1,结果是 256。当以二进制数组格式完成时,255 值将是 00000000FF 并且 1 是字节的十六进制表示形式的 0000000001 值。预期的结果将是 0000000100.

我的以下代码尝试将 255 的 5 字节数组递增 1。我的最终结果是 00000001FE,最后一个字节 0xFE 应该是 0x00。如何通过仅使用基本二进制操作数(嵌入 Java 环境)来更正我的算法以正确执行 5 字节数组增量?

    private static byte[] clkCtrCurr = new byte[5];
    private static byte[] inc = {0x00, 0x00, 0x00, 0x00, 0x01};
    private static byte buff;
    private static byte carry;

    public static void binAdd() {
        buff = (byte) (clkCtrCurr[4] ^ inc[4]);
        carry = (byte) (clkCtrCurr[4] & inc[4]);
        clkCtrCurr[4] = buff;
        clkCtrCurr[3] ^= carry;
        buff = (byte) (clkCtrCurr[3] ^ inc[3]);
        carry = (byte) (clkCtrCurr[3] & inc[3]);
        clkCtrCurr[3] = buff;
        clkCtrCurr[2] ^= carry;
        buff = (byte) (clkCtrCurr[2] ^ inc[2]);
        carry = (byte) (clkCtrCurr[2] & inc[2]);
        clkCtrCurr[2] = buff;
        clkCtrCurr[1] ^= carry;
        buff = (byte) (clkCtrCurr[1] ^ inc[1]);
        carry = (byte) (clkCtrCurr[1] & inc[1]);
        clkCtrCurr[1] = buff;
        clkCtrCurr[0] ^= carry;
        clkCtrCurr[0] ^= inc[0];
    }

BCD format 表示每个十进制数字 (0-9) 以 4 位存储(如果未压缩则为 8 位),这意味着该数字以十六进制打印时看起来是十进制的。

例子:十进制数123应该用BCD存储为0x0123(十进制291)。

如果解压,它只是 3 个字节:0x01 0x02 0x030x010203(十进制 66051)。

因此,如果您想要一个 5 字节打包的大端 BCD 数,即一个 10 位十进制数,并且您想要递增,您可以这样做:

private static void increment(byte[] bcd) {
    for (int i = bcd.length - 1; i >= 0; i--) {
        byte b = bcd[i];
        if ((b & 0x0F) < 0x09) {
            bcd[i] = (byte)(b + 1);
            return;
        }
        if ((b & 0xF0) < 0x90) {
            bcd[i] = (byte)((b & 0xF0) + 0x10);
            return;
        }
        bcd[i] = 0;
    }
}

测试

private static void print(byte[] bcd) {
    for (int i = 0; i < bcd.length; i++) {
        if (i != 0)
            System.out.print(' ');
        System.out.printf("%02x", bcd[i]);
    }
    System.out.println();
}
public static void main(String[] args) {
    byte[] bcd1 = { 0x00, 0x00, 0x00, 0x01, 0x23 }; // decimal 123
    for (int i = 0; i < 10; i++) {
        increment(bcd1);
        print(bcd1);
    }
    byte[] bcd2 = { (byte)0x99, (byte)0x99, (byte)0x99, (byte)0x99, (byte)0x95 }; // decimal 9_999_999_995
    for (int i = 0; i < 10; i++) {
        increment(bcd2);
        print(bcd2);
    }
}

输出

00 00 00 01 24
00 00 00 01 25
00 00 00 01 26
00 00 00 01 27
00 00 00 01 28
00 00 00 01 29
00 00 00 01 30
00 00 00 01 31
00 00 00 01 32
00 00 00 01 33
99 99 99 99 96
99 99 99 99 97
99 99 99 99 98
99 99 99 99 99
00 00 00 00 00
00 00 00 00 01
00 00 00 00 02
00 00 00 00 03
00 00 00 00 04
00 00 00 00 05

试试这个。

static byte add(byte x, byte y, byte[] result, byte index) {
    byte c = 0;
    while (y != 0) {
        byte t = (byte)(x & y);
        c |= t;
        x = (byte)(x ^ y);
        y = (byte)(t << 1);
    }
    result[index] = x;
    return (byte)((c & 0x80) != 0 ? 1 : 0);
}

static byte add(byte a, byte b, byte c, byte[] result, byte index) {
    byte carry = add(a, b, result, index);
    if (c > 0)
        carry |= add(result[index], c, result, index);
    return carry;
}

public static void add(byte[] a, byte[] b) {
    byte c = 0;
    c = add(a[4], b[4], c, a, (byte)4);
    c = add(a[3], b[3], c, a, (byte)3);
    c = add(a[2], b[2], c, a, (byte)2);
    c = add(a[1], b[1], c, a, (byte)1);
    c = add(a[0], b[0], c, a, (byte)0);
}