diff --git a/algorithms-modules/algorithms-numeric/pom.xml b/algorithms-modules/algorithms-numeric/pom.xml
index 444a3ccd19e7..9ab0a0222b86 100644
--- a/algorithms-modules/algorithms-numeric/pom.xml
+++ b/algorithms-modules/algorithms-numeric/pom.xml
@@ -24,10 +24,19 @@
jmh-generator-annprocess
${jmh.version}
+
+
+ org.apache.commons
+ commons-math3
+ ${commons-math3.version}
+
+
+
+ org.junit.jupiter
+ junit-jupiter
+ ${junit.jupiter.version}
+ test
+
-
- 1.35
-
-
\ No newline at end of file
diff --git a/algorithms-modules/algorithms-numeric/src/main/java/com/baeldung/algorithms/bcdtodecimal/BCDtoDecimalConverter.java b/algorithms-modules/algorithms-numeric/src/main/java/com/baeldung/algorithms/bcdtodecimal/BCDtoDecimalConverter.java
new file mode 100644
index 000000000000..1549f79f9e50
--- /dev/null
+++ b/algorithms-modules/algorithms-numeric/src/main/java/com/baeldung/algorithms/bcdtodecimal/BCDtoDecimalConverter.java
@@ -0,0 +1,48 @@
+package com.baeldung.algorithms.bcdtodecimal;
+
+public class BCDtoDecimalConverter {
+ /**
+ * Converts a single packed BCD byte to an integer.
+ * Each byte represents two decimal digits.
+ *
+ * @param bcdByte The BCD byte to convert.
+ * @return The decimal integer value.
+ * @throws IllegalArgumentException if any nibble contains a non-BCD value (>9).
+ */
+ public static int convertPackedByte(byte bcdByte) {
+ int resultDecimal;
+ int upperNibble = (bcdByte >> 4) & 0x0F;
+ int lowerNibble = bcdByte & 0x0F;
+ if (upperNibble > 9 || lowerNibble > 9) {
+ throw new IllegalArgumentException(
+ String.format("Invalid BCD format: byte 0x%02X contains non-decimal digit.", bcdByte)
+ );
+ }
+ resultDecimal = upperNibble * 10 + lowerNibble;
+ return resultDecimal;
+ }
+
+ /**
+ * Converts a BCD byte array to a long decimal value.
+ * Each byte in the array iis mapped to a packed BCD byte,
+ * representing two BCD nibbles.
+ *
+ * @param bcdArray The array of BCD bytes.
+ * @return The combined long decimal value.
+ * @throws IllegalArgumentException if any nibble contains a non-BCD value (>9).
+ */
+ public static long convertPackedByteArray(byte[] bcdArray) {
+ long resultDecimal = 0;
+ for (byte bcd : bcdArray) {
+ int upperNibble = (bcd >> 4) & 0x0F;
+ int lowerNibble = bcd & 0x0F;
+
+ if (upperNibble > 9 || lowerNibble > 9) {
+ throw new IllegalArgumentException("Invalid BCD format: nibble contains non-decimal digit.");
+ }
+
+ resultDecimal = resultDecimal * 100 + (upperNibble * 10 + lowerNibble);
+ }
+ return resultDecimal;
+ }
+}
\ No newline at end of file
diff --git a/algorithms-modules/algorithms-numeric/src/main/java/com/baeldung/algorithms/twoanglesdifference/AngleDifferenceCalculator.java b/algorithms-modules/algorithms-numeric/src/main/java/com/baeldung/algorithms/twoanglesdifference/AngleDifferenceCalculator.java
new file mode 100644
index 000000000000..0edd5d31f377
--- /dev/null
+++ b/algorithms-modules/algorithms-numeric/src/main/java/com/baeldung/algorithms/twoanglesdifference/AngleDifferenceCalculator.java
@@ -0,0 +1,64 @@
+/**
+ * Package to host code for calculating three types of angle difference
+ */
+package com.baeldung.algorithms.twoanglesdifference;
+
+public class AngleDifferenceCalculator {
+
+ /**
+ * Normalizes an angle to be within the range [0, 360).
+ *
+ * @param angle The angle in degrees.
+ * @return The normalized angle.
+ */
+ public static double normalizeAngle(double angle) {
+ return (angle % 360 + 360) % 360;
+ }
+
+ /**
+ * Calculates the absolute difference between two angles.
+ *
+ * @param angle1 The first angle in degrees.
+ * @param angle2 The second angle in degrees.
+ * @return The absolute difference in degrees.
+ */
+ public static double absoluteDifference(double angle1, double angle2) {
+ return Math.abs(angle1 - angle2);
+ }
+
+ /**
+ * Calculates the shortest difference between two angles.
+ *
+ * @param angle1 The first angle in degrees.
+ * @param angle2 The second angle in degrees.
+ * @return The shortest difference in degrees (0 to 180).
+ */
+ public static double shortestDifference(double angle1, double angle2) {
+ double diff = absoluteDifference(normalizeAngle(angle1), normalizeAngle(angle2));
+ return Math.min(diff, 360 - diff);
+ }
+
+ /**
+ * Calculates the signed shortest difference between two angles.
+ * A positive result indicates counter-clockwise rotation, a negative result indicates clockwise.
+ *
+ * @param angle1 The first angle in degrees.
+ * @param angle2 The second angle in degrees.
+ * @return The signed shortest difference in degrees (-180 to 180).
+ */
+ public static double signedShortestDifference(double angle1, double angle2) {
+ double normalizedAngle1 = normalizeAngle(angle1);
+ double normalizedAngle2 = normalizeAngle(angle2);
+ double diff = normalizedAngle2 - normalizedAngle1;
+
+ if (diff > 180) {
+ return diff - 360;
+ } else if (diff < -180) {
+ return diff + 360;
+ } else {
+ return diff;
+ }
+ }
+}
+
+
diff --git a/algorithms-modules/algorithms-numeric/src/test/java/com/baeldung/algorithms/bcdtodecimal/BCDtoDecimalConverterTest.java b/algorithms-modules/algorithms-numeric/src/test/java/com/baeldung/algorithms/bcdtodecimal/BCDtoDecimalConverterTest.java
new file mode 100644
index 000000000000..746f463d432d
--- /dev/null
+++ b/algorithms-modules/algorithms-numeric/src/test/java/com/baeldung/algorithms/bcdtodecimal/BCDtoDecimalConverterTest.java
@@ -0,0 +1,95 @@
+package com.baeldung.algorithms.bcdtodecimal;
+
+import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+public class BCDtoDecimalConverterTest {
+
+ // 1. Tests for convertPackedByte(byte bcdByte)
+
+ @Test
+ void testConvertPackedByteValidValues() {
+ // Test 05 (0x05) ->
+ assertEquals(5, BCDtoDecimalConverter.convertPackedByte((byte) 0x05));
+
+ // Test 22 (0x22) -> 22
+ assertEquals(22, BCDtoDecimalConverter.convertPackedByte((byte) 0x22));
+
+ // Test 97 (0x097) -> 97
+ assertEquals(97, BCDtoDecimalConverter.convertPackedByte((byte) 0x097));
+ }
+
+ @Test
+ void testConvertPackedByteInvalidUpperNibbleThrowsException() {
+ // Test Upper nibble is A (1010), Lower nibble is 1 (0001) -> 0xA1
+ byte invalidByte = (byte) 0xA1;
+ assertThrows(IllegalArgumentException.class, () -> BCDtoDecimalConverter.convertPackedByte(invalidByte),
+ "Received non-BCD upper nibble (A). Provide valid BCD nibbles (0-9).");
+ }
+
+ @Test
+ void testConvertPackedByteBothInvalidThrowsException() {
+ // test Upper nibble is B, Lower nibble is E -> 0xBE
+ byte invalidByte = (byte) 0xBE;
+ assertThrows(IllegalArgumentException.class,
+ () -> BCDtoDecimalConverter.convertPackedByte(invalidByte),
+ "Received both nibbles as non-BCD. Provide valid BCD nibbles (0-9)."
+ );
+ }
+
+ // -------------------------------------------------------------------------
+
+ // 2. Tests for convertPackedByteArray(byte[] bcdArray)
+
+ @Test
+ void testConvertPackedByteArrayValidValues() {
+ // Test 0 -> [0x00]
+ assertEquals(0L, BCDtoDecimalConverter.convertPackedByteArray(new byte[]{(byte) 0x00}));
+
+ // Test 99 -> [0x99]
+ assertEquals(99L, BCDtoDecimalConverter.convertPackedByteArray(new byte[]{(byte) 0x99}));
+
+ // Test 1234 -> [0x12, 0x34]
+ byte[] bcd1234 = {(byte) 0x12, (byte) 0x34};
+ assertEquals(1234L, BCDtoDecimalConverter.convertPackedByteArray(bcd1234));
+
+ // Test 12345678 -> [0x12, 0x34, 0x56, 0x78]
+ byte[] bcdLarge = {(byte) 0x12, (byte) 0x34, (byte) 0x56, (byte) 0x78};
+ assertEquals(12345678L, BCDtoDecimalConverter.convertPackedByteArray(bcdLarge));
+ }
+
+ @Test
+ void testConvertPackedByteArrayEmptyArray() {
+ // Test empty array -> 0
+ assertEquals(0L, BCDtoDecimalConverter.convertPackedByteArray(new byte[]{}));
+ }
+
+ @Test
+ void testConvertPackedByteArrayMaximumSafeLong() {
+ // Test a large number that fits within a long (18 digits)
+ // 999,999,999,999,999,999 (18 nines)
+ byte[] bcdMax = {(byte) 0x99, (byte) 0x99, (byte) 0x99, (byte) 0x99, (byte) 0x99, (byte) 0x99, (byte) 0x99, (byte) 0x99, (byte) 0x99};
+ assertEquals(999999999999999999L, BCDtoDecimalConverter.convertPackedByteArray(bcdMax));
+ }
+
+ @Test
+ void testConvertPackedByteArrayInvalidNibbleThrowsException() {
+ // Contains 0x1A (A is an invalid BCD digit)
+ byte[] bcdInvalid = {(byte) 0x12, (byte) 0x1A, (byte) 0x34};
+ assertThrows(IllegalArgumentException.class,
+ () -> BCDtoDecimalConverter.convertPackedByteArray(bcdInvalid),
+ "Received array containing an invalid BCD byte. Provide valid BCD nibbles (0-9)."
+ );
+ }
+
+ @Test
+ void testConvertPackedByteArray_InvalidFirstByteThrowsException() {
+ // Invalid BCD byte at the start
+ byte[] bcdInvalid = {(byte) 0xF0, (byte) 0x12};
+ assertThrows(IllegalArgumentException.class,
+ () -> BCDtoDecimalConverter.convertPackedByteArray(bcdInvalid),
+ "Received first byte as an invalid BCD byte. Provide valid BCD nibbles (0-9)."
+ );
+ }
+}
\ No newline at end of file
diff --git a/algorithms-modules/algorithms-numeric/src/test/java/com/baeldung/algorithms/twoanglesdifference/AngleDifferenceCalculatorTest.java b/algorithms-modules/algorithms-numeric/src/test/java/com/baeldung/algorithms/twoanglesdifference/AngleDifferenceCalculatorTest.java
new file mode 100644
index 000000000000..1539c6b9e37b
--- /dev/null
+++ b/algorithms-modules/algorithms-numeric/src/test/java/com/baeldung/algorithms/twoanglesdifference/AngleDifferenceCalculatorTest.java
@@ -0,0 +1,47 @@
+/**
+ * Package to host JUnit Test code for AngleDifferenceCalculator Class
+ */
+package com.baeldung.algorithms.twoanglesdifference;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+
+
+class AngleDifferenceCalculatorTest {
+
+ private static final double EPSILON = 0.0001;
+
+ @Test
+ void whenNormalizingAngle_thenReturnsCorrectRange() {
+ assertEquals(90, AngleDifferenceCalculator.normalizeAngle(450), EPSILON);
+ assertEquals(30, AngleDifferenceCalculator.normalizeAngle(390), EPSILON);
+ assertEquals(330, AngleDifferenceCalculator.normalizeAngle(-30), EPSILON);
+ assertEquals(0, AngleDifferenceCalculator.normalizeAngle(360), EPSILON);
+ }
+
+ @Test
+ void whenCalculatingAbsoluteDifference_thenReturnsCorrectValue() {
+ assertEquals(100, AngleDifferenceCalculator.absoluteDifference(10, 110), EPSILON);
+ assertEquals(290, AngleDifferenceCalculator.absoluteDifference(10, 300), EPSILON);
+ assertEquals(30, AngleDifferenceCalculator.absoluteDifference(-30, 0), EPSILON);
+ }
+
+ @Test
+ void whenCalculatingShortestDifference_thenReturnsCorrectValue() {
+ assertEquals(100, AngleDifferenceCalculator.shortestDifference(10, 110), EPSILON);
+ assertEquals(70, AngleDifferenceCalculator.shortestDifference(10, 300), EPSILON);
+ assertEquals(30, AngleDifferenceCalculator.shortestDifference(-30, 0), EPSILON);
+ assertEquals(0, AngleDifferenceCalculator.shortestDifference(360, 0), EPSILON);
+ }
+
+ @Test
+ void whenCalculatingSignedShortestDifference_thenReturnsCorrectValue() {
+ assertEquals(100, AngleDifferenceCalculator.signedShortestDifference(10, 110), EPSILON);
+ assertEquals(-70, AngleDifferenceCalculator.signedShortestDifference(10, 300), EPSILON);
+ assertEquals(30, AngleDifferenceCalculator.signedShortestDifference(-30, 0), EPSILON);
+ assertEquals(70, AngleDifferenceCalculator.signedShortestDifference(300, 10), EPSILON);
+ }
+}
+
diff --git a/pom.xml b/pom.xml
index d1c3684de872..dae917ff1966 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,4 +1,4 @@
-
+
}
+ *
+ * @param value
+ * Java instance representing xml element's value.
+ * @return
+ * the new instance of {@link JAXBElement }{@code <}{@link UserRequest }{@code >}
+ */
+ @XmlElementDecl(namespace = "http://www.baeldung.com/jaxb/gen", name = "userRequest")
+ public JAXBElement createUserRequest(UserRequest value) {
+ return new JAXBElement(_UserRequest_QNAME, UserRequest.class, null, value);
+ }
+
+ /**
+ * Create an instance of {@link JAXBElement }{@code <}{@link UserResponse }{@code >}
+ *
+ * @param value
+ * Java instance representing xml element's value.
+ * @return
+ * the new instance of {@link JAXBElement }{@code <}{@link UserResponse }{@code >}
+ */
+ @XmlElementDecl(namespace = "http://www.baeldung.com/jaxb/gen", name = "userResponse")
+ public JAXBElement createUserResponse(UserResponse value) {
+ return new JAXBElement(_UserResponse_QNAME, UserResponse.class, null, value);
+ }
+
}
diff --git a/xml-modules/jaxb/src/main/java/com/baeldung/jaxb/gen/UserRequest.java b/xml-modules/jaxb/src/main/java/com/baeldung/jaxb/gen/UserRequest.java
index 7ba9064e9ea8..a2bb28f0b884 100644
--- a/xml-modules/jaxb/src/main/java/com/baeldung/jaxb/gen/UserRequest.java
+++ b/xml-modules/jaxb/src/main/java/com/baeldung/jaxb/gen/UserRequest.java
@@ -1,11 +1,9 @@
package com.baeldung.jaxb.gen;
-import java.io.Serializable;
import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType;
import jakarta.xml.bind.annotation.XmlElement;
-import jakarta.xml.bind.annotation.XmlRootElement;
import jakarta.xml.bind.annotation.XmlType;
@@ -34,12 +32,8 @@
"id",
"name"
})
-@XmlRootElement(name = "userRequest")
-public class UserRequest
- implements Serializable
-{
+public class UserRequest {
- private final static long serialVersionUID = -1L;
protected int id;
@XmlElement(required = true)
protected String name;
diff --git a/xml-modules/jaxb/src/main/java/com/baeldung/jaxb/gen/UserResponse.java b/xml-modules/jaxb/src/main/java/com/baeldung/jaxb/gen/UserResponse.java
index f35b001a689c..e398b639b08b 100644
--- a/xml-modules/jaxb/src/main/java/com/baeldung/jaxb/gen/UserResponse.java
+++ b/xml-modules/jaxb/src/main/java/com/baeldung/jaxb/gen/UserResponse.java
@@ -1,16 +1,12 @@
package com.baeldung.jaxb.gen;
-import java.io.Serializable;
-import java.util.Calendar;
+import javax.xml.datatype.XMLGregorianCalendar;
import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType;
import jakarta.xml.bind.annotation.XmlElement;
-import jakarta.xml.bind.annotation.XmlRootElement;
import jakarta.xml.bind.annotation.XmlSchemaType;
import jakarta.xml.bind.annotation.XmlType;
-import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
-import org.w3._2001.xmlschema.Adapter1;
/**
@@ -42,21 +38,16 @@
"gender",
"created"
})
-@XmlRootElement(name = "userResponse")
-public class UserResponse
- implements Serializable
-{
+public class UserResponse {
- private final static long serialVersionUID = -1L;
protected int id;
@XmlElement(required = true)
protected String name;
@XmlElement(required = true)
protected String gender;
- @XmlElement(required = true, type = String.class)
- @XmlJavaTypeAdapter(Adapter1 .class)
+ @XmlElement(required = true)
@XmlSchemaType(name = "dateTime")
- protected Calendar created;
+ protected XMLGregorianCalendar created;
/**
* Gets the value of the id property.
@@ -127,10 +118,10 @@ public void setGender(String value) {
*
* @return
* possible object is
- * {@link String }
+ * {@link XMLGregorianCalendar }
*
*/
- public Calendar getCreated() {
+ public XMLGregorianCalendar getCreated() {
return created;
}
@@ -139,10 +130,10 @@ public Calendar getCreated() {
*
* @param value
* allowed object is
- * {@link String }
+ * {@link XMLGregorianCalendar }
*
*/
- public void setCreated(Calendar value) {
+ public void setCreated(XMLGregorianCalendar value) {
this.created = value;
}