#include "../../unity/unity.h" #include #include #include #include #include /* Helper: absolute value for long double without libm dependency */ static long double ldabs(long double x) { return x < 0 ? -x : x; } /* Helper: assert two long doubles are approximately equal */ static void assert_ld_close(long double expected, long double actual, long double tol, const char* msg) { long double diff = ldabs(expected - actual); if (diff > tol) { char buf[256]; snprintf(buf, sizeof(buf), "%s: expected %.18Lg but got %.18Lg (diff=%.18Lg, tol=%.18Lg)", msg ? msg : "Mismatch", expected, actual, diff, tol); TEST_FAIL_MESSAGE(buf); } } /* Unity fixtures */ void setUp(void) { /* no global state to set for expld() */ } void tearDown(void) { /* nothing to clean up */ } /* Tests */ static void test_expld_abs_less_than_base(void) { int x = -1; long double in = 9.5L; long double out = expld(in, 10, &x); TEST_ASSERT_EQUAL_INT_MESSAGE(0, x, "power should be 0 when |val| < base"); assert_ld_close(in, out, 1e-15L, "value should be unchanged when |val| < base"); } static void test_expld_exact_power_of_base(void) { int x = -1; long double in = 1000.0L; /* 10^3 */ long double out = expld(in, 10, &x); TEST_ASSERT_EQUAL_INT_MESSAGE(3, x, "power should be 3 for 10^3"); assert_ld_close(1.0L, out, 1e-18L, "scaled value should be 1.0 for 10^3"); } static void test_expld_negative_value(void) { int x = -1; long double in = -12345.0L; long double out = expld(in, 10, &x); TEST_ASSERT_EQUAL_INT_MESSAGE(4, x, "power should be 4 for |-12345|"); /* Expected: -1.2345 */ assert_ld_close(-1.2345L, out, 1e-15L, "scaled value mismatch for negative input"); } static void test_expld_base_1024_exact(void) { int x = -1; long double in = 5.0L * powerld(1024.0L, 2); /* 5 * 1024^2 */ long double out = expld(in, 1024, &x); TEST_ASSERT_EQUAL_INT_MESSAGE(2, x, "power should be 2 for 5*1024^2"); assert_ld_close(5.0L, out, 1e-18L, "scaled value should be exactly 5.0"); } static void test_expld_zero_value(void) { int x = -1; long double out = expld(0.0L, 10, &x); TEST_ASSERT_EQUAL_INT_MESSAGE(0, x, "power should be 0 for input 0"); assert_ld_close(0.0L, out, 0.0L, "output should be 0 for input 0"); } static void test_expld_null_x_pointer(void) { long double in = 2048.0L; /* 2 * 1024 */ long double out = expld(in, 1024, NULL); /* Should scale to 2.0, but we cannot check x as it's NULL; ensure no crash and correct value */ assert_ld_close(2.0L, out, 1e-18L, "scaled value should be 2.0 when x is NULL"); } static void test_expld_fractional_scaling_and_reversibility(void) { int x = -1; long double base = 10.0L; int k = 6; long double mantissa = 7.25L; long double in = mantissa * powerld(base, k); /* 7.25e6 */ long double out = expld(in, (int)base, &x); TEST_ASSERT_EQUAL_INT_MESSAGE(k, x, "power should equal the constructed exponent"); assert_ld_close(mantissa, out, 1e-12L, "scaled mantissa mismatch"); /* Verify |out| < base and reconstruction property approximately holds */ TEST_ASSERT_TRUE_MESSAGE(ldabs(out) < base, "|scaled value| should be < base"); long double recon = out; for (int i = 0; i < x; i++) recon *= base; /* Use relative tolerance for large numbers */ long double rel_tol = 1e-12L; long double tol = ldabs(in) * rel_tol + 1e-6L; assert_ld_close(in, recon, tol, "reconstructed value mismatch"); } static void test_expld_fractional_input_base10(void) { int x = -1; long double in = 123.456L; long double out = expld(in, 10, &x); TEST_ASSERT_EQUAL_INT_MESSAGE(2, x, "power should be 2 for 123.456 with base 10"); assert_ld_close(1.23456L, out, 1e-15L, "scaled value mismatch for 123.456"); } static void test_expld_nan_input_sets_x_zero_and_returns_nan(void) { int x = -1; long double nanval = (long double)NAN; long double out = expld(nanval, 10, &x); TEST_ASSERT_EQUAL_INT_MESSAGE(0, x, "power should be 0 for NaN input"); TEST_ASSERT_TRUE_MESSAGE(out != out, "output should be NaN (NaN != NaN)"); } int main(void) { UNITY_BEGIN(); RUN_TEST(test_expld_abs_less_than_base); RUN_TEST(test_expld_exact_power_of_base); RUN_TEST(test_expld_negative_value); RUN_TEST(test_expld_base_1024_exact); RUN_TEST(test_expld_zero_value); RUN_TEST(test_expld_null_x_pointer); RUN_TEST(test_expld_fractional_scaling_and_reversibility); RUN_TEST(test_expld_fractional_input_base10); RUN_TEST(test_expld_nan_input_sets_x_zero_and_returns_nan); return UNITY_END(); }