I propose using BCD addition and BCD subtraction, as follow:
- Each byte represent two BCD, e.g. 0x99 represent 99 instead of 153.
- All data included in the addition and subtraction shall have the same length, e.g. 6 bytes will represents 12 digits. This should cover most cases, but if you need more, simply change your constant.
- Your applet performs loop through the bytes to do the addition or subtraction. Encode and decode operation from BCD to the value and vice versa are needed before and after the operation.
Here is sample for the implementation. It is not tested yet, but should give you idea of how it works:
public class BCD {
public static final short NUMBER_OF_BYTES = 6;
static void add(byte[] augend, byte[] addend, byte[] result) {
byte carry = 0;
short temp = 0;
for (short i = (short) (NUMBER_OF_BYTES - 1); i >= 0; i--) {
temp = (short) (decode(augend[i]) + decode(addend[i]) + carry);
carry = (byte) ((temp > 100) ? 1 : 0);
result[i] = encode((byte) temp);
}
if (carry == 1) {
// TODO: result more than maximum
// you can set all digits to 9 or throw exception
}
}
static void subtract(byte[] minuend, byte[] subtrahend, byte[] result) {
byte borrow = 0;
short temp = 0;
for (short i = (short) (NUMBER_OF_BYTES - 1); i >= 0; i--) {
temp = (short) (100 + decode(minuend[i]) - decode(subtrahend[i]) - borrow);
borrow = (byte) ((temp < 100) ? 1 : 0);
result[i] = encode((byte) temp);
}
if (borrow == 1) {
// TODO: subtrahend > minuend,
// you can set all digits to 0 or throw exception
}
}
static byte encode(byte value) {
value %= 100; // only convert two digits, ignore borrow/carry
return (byte) (((value / 10) << 4) | (value % 10));
}
static byte decode(byte bcdByte) {
byte highNibble = (byte) ((bcdByte >> 4) & 0x0F);
byte lowNibble = (byte) (bcdByte & 0x0F);
if ((highNibble > 9) || (lowNibble > 9)) {
// found 'A' to 'F' character which should be invalid
// you can change this line, e.g. throwing exception
return 0;
}
return (byte) ((highNibble * 10) + lowNibble);
}
}