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; }