Skip to content

Commit 669574c

Browse files
BAEL-9186 Convert BCD to Decimal (#18876)
Co-authored-by: Nikhil Bhargava <[email protected]>
1 parent a6c960e commit 669574c

File tree

2 files changed

+143
-0
lines changed

2 files changed

+143
-0
lines changed
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package com.baeldung.algorithms.bcdtodecimal;
2+
3+
public class BCDtoDecimalConverter {
4+
/**
5+
* Converts a single packed BCD byte to an integer.
6+
* Each byte represents two decimal digits.
7+
*
8+
* @param bcdByte The BCD byte to convert.
9+
* @return The decimal integer value.
10+
* @throws IllegalArgumentException if any nibble contains a non-BCD value (>9).
11+
*/
12+
public static int convertPackedByte(byte bcdByte) {
13+
int resultDecimal;
14+
int upperNibble = (bcdByte >> 4) & 0x0F;
15+
int lowerNibble = bcdByte & 0x0F;
16+
if (upperNibble > 9 || lowerNibble > 9) {
17+
throw new IllegalArgumentException(
18+
String.format("Invalid BCD format: byte 0x%02X contains non-decimal digit.", bcdByte)
19+
);
20+
}
21+
resultDecimal = upperNibble * 10 + lowerNibble;
22+
return resultDecimal;
23+
}
24+
25+
/**
26+
* Converts a BCD byte array to a long decimal value.
27+
* Each byte in the array iis mapped to a packed BCD byte,
28+
* representing two BCD nibbles.
29+
*
30+
* @param bcdArray The array of BCD bytes.
31+
* @return The combined long decimal value.
32+
* @throws IllegalArgumentException if any nibble contains a non-BCD value (>9).
33+
*/
34+
public static long convertPackedByteArray(byte[] bcdArray) {
35+
long resultDecimal = 0;
36+
for (byte bcd : bcdArray) {
37+
int upperNibble = (bcd >> 4) & 0x0F;
38+
int lowerNibble = bcd & 0x0F;
39+
40+
if (upperNibble > 9 || lowerNibble > 9) {
41+
throw new IllegalArgumentException("Invalid BCD format: nibble contains non-decimal digit.");
42+
}
43+
44+
resultDecimal = resultDecimal * 100 + (upperNibble * 10 + lowerNibble);
45+
}
46+
return resultDecimal;
47+
}
48+
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package com.baeldung.algorithms.bcdtodecimal;
2+
3+
import org.junit.jupiter.api.Test;
4+
import static org.junit.jupiter.api.Assertions.assertEquals;
5+
import static org.junit.jupiter.api.Assertions.assertThrows;
6+
7+
public class BCDtoDecimalConverterTest {
8+
9+
// 1. Tests for convertPackedByte(byte bcdByte)
10+
11+
@Test
12+
void testConvertPackedByteValidValues() {
13+
// Test 05 (0x05) ->
14+
assertEquals(5, BCDtoDecimalConverter.convertPackedByte((byte) 0x05));
15+
16+
// Test 22 (0x22) -> 22
17+
assertEquals(22, BCDtoDecimalConverter.convertPackedByte((byte) 0x22));
18+
19+
// Test 97 (0x097) -> 97
20+
assertEquals(97, BCDtoDecimalConverter.convertPackedByte((byte) 0x097));
21+
}
22+
23+
@Test
24+
void testConvertPackedByteInvalidUpperNibbleThrowsException() {
25+
// Test Upper nibble is A (1010), Lower nibble is 1 (0001) -> 0xA1
26+
byte invalidByte = (byte) 0xA1;
27+
assertThrows(IllegalArgumentException.class, () -> BCDtoDecimalConverter.convertPackedByte(invalidByte),
28+
"Received non-BCD upper nibble (A). Provide valid BCD nibbles (0-9).");
29+
}
30+
31+
@Test
32+
void testConvertPackedByteBothInvalidThrowsException() {
33+
// test Upper nibble is B, Lower nibble is E -> 0xBE
34+
byte invalidByte = (byte) 0xBE;
35+
assertThrows(IllegalArgumentException.class,
36+
() -> BCDtoDecimalConverter.convertPackedByte(invalidByte),
37+
"Received both nibbles as non-BCD. Provide valid BCD nibbles (0-9)."
38+
);
39+
}
40+
41+
// -------------------------------------------------------------------------
42+
43+
// 2. Tests for convertPackedByteArray(byte[] bcdArray)
44+
45+
@Test
46+
void testConvertPackedByteArrayValidValues() {
47+
// Test 0 -> [0x00]
48+
assertEquals(0L, BCDtoDecimalConverter.convertPackedByteArray(new byte[]{(byte) 0x00}));
49+
50+
// Test 99 -> [0x99]
51+
assertEquals(99L, BCDtoDecimalConverter.convertPackedByteArray(new byte[]{(byte) 0x99}));
52+
53+
// Test 1234 -> [0x12, 0x34]
54+
byte[] bcd1234 = {(byte) 0x12, (byte) 0x34};
55+
assertEquals(1234L, BCDtoDecimalConverter.convertPackedByteArray(bcd1234));
56+
57+
// Test 12345678 -> [0x12, 0x34, 0x56, 0x78]
58+
byte[] bcdLarge = {(byte) 0x12, (byte) 0x34, (byte) 0x56, (byte) 0x78};
59+
assertEquals(12345678L, BCDtoDecimalConverter.convertPackedByteArray(bcdLarge));
60+
}
61+
62+
@Test
63+
void testConvertPackedByteArrayEmptyArray() {
64+
// Test empty array -> 0
65+
assertEquals(0L, BCDtoDecimalConverter.convertPackedByteArray(new byte[]{}));
66+
}
67+
68+
@Test
69+
void testConvertPackedByteArrayMaximumSafeLong() {
70+
// Test a large number that fits within a long (18 digits)
71+
// 999,999,999,999,999,999 (18 nines)
72+
byte[] bcdMax = {(byte) 0x99, (byte) 0x99, (byte) 0x99, (byte) 0x99, (byte) 0x99, (byte) 0x99, (byte) 0x99, (byte) 0x99, (byte) 0x99};
73+
assertEquals(999999999999999999L, BCDtoDecimalConverter.convertPackedByteArray(bcdMax));
74+
}
75+
76+
@Test
77+
void testConvertPackedByteArrayInvalidNibbleThrowsException() {
78+
// Contains 0x1A (A is an invalid BCD digit)
79+
byte[] bcdInvalid = {(byte) 0x12, (byte) 0x1A, (byte) 0x34};
80+
assertThrows(IllegalArgumentException.class,
81+
() -> BCDtoDecimalConverter.convertPackedByteArray(bcdInvalid),
82+
"Received array containing an invalid BCD byte. Provide valid BCD nibbles (0-9)."
83+
);
84+
}
85+
86+
@Test
87+
void testConvertPackedByteArray_InvalidFirstByteThrowsException() {
88+
// Invalid BCD byte at the start
89+
byte[] bcdInvalid = {(byte) 0xF0, (byte) 0x12};
90+
assertThrows(IllegalArgumentException.class,
91+
() -> BCDtoDecimalConverter.convertPackedByteArray(bcdInvalid),
92+
"Received first byte as an invalid BCD byte. Provide valid BCD nibbles (0-9)."
93+
);
94+
}
95+
}

0 commit comments

Comments
 (0)