|
|
#include "../../unity/unity.h" |
|
|
#include <stdio.h> |
|
|
#include <stdlib.h> |
|
|
#include <string.h> |
|
|
#include <float.h> |
|
|
#include <math.h> |
|
|
|
|
|
|
|
|
static long double ldabs(long double x) { return x < 0 ? -x : x; } |
|
|
|
|
|
|
|
|
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); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void setUp(void) { |
|
|
|
|
|
} |
|
|
void tearDown(void) { |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
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; |
|
|
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|"); |
|
|
|
|
|
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); |
|
|
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; |
|
|
long double out = expld(in, 1024, NULL); |
|
|
|
|
|
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); |
|
|
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"); |
|
|
|
|
|
|
|
|
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; |
|
|
|
|
|
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(); |
|
|
} |