File size: 4,766 Bytes
78d2150
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#include "../../unity/unity.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <float.h>
#include <math.h>

/* 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();
}