#include "c_float.h" #include #include #include /* ------------------------------------------------------------------------------------------------------------------ */ /* */ /** * @brief 辅助工具:将 C 语言原生双精度 double 转换为 64 位原始位码 (uint64_t) */ static uint64_t to_raw64(double d) { c_Double_t u; u.d = d; return u.raw; } /** * @brief 辅助工具:将 64 位原始位码 (uint64_t) 还原为 C 语言原生双精度 double */ static double to_double(uint64_t raw) { c_Double_t u; u.raw = raw; return u.d; } /* ------------------------------------------------------------------------------------------------------------------ */ /* */ // 用例 1:测试 Float 分类状态识别函数(IsZero, IsInf, IsNAN 等基本位打包判定) void test_float_classification_and_pack() { c_Float_t val; // 1. 测试 Pack 是否能准确组装成标准浮点位 // 符号=0, 指数=127(偏移后为0), 尾数=0 -> 应该代表 1.0f uint32_t packed = c_Float_Pack(0, 127, 0); val.raw = packed; ASSERT_MSG(val.f == 1.0f, "c_Float_Pack failed to assemble 1.0f"); // 2. 测试 正负零 (0.0f 和 -0.0f) val.f = 0.0f; ASSERT_MSG(c_Float_IsZero(val.raw) == true, "0.0f should be identified as zero"); val.f = -0.0f; ASSERT_MSG(c_Float_IsZero(val.raw) == true, "-0.0f should be identified as zero"); // 3. 测试 正负无穷大 (Inf) val.raw = C_FLOAT_POS_INF; ASSERT_MSG(c_Float_IsInf(val.raw) == true, "POS_INF must be Inf"); ASSERT_MSG(c_Float_IsPosInf(val.raw) == true, "POS_INF must be PosInf"); val.raw = C_FLOAT_NEG_INF; ASSERT_MSG(c_Float_IsInf(val.raw) == true, "NEG_INF must be Inf"); ASSERT_MSG(c_Float_IsNegInf(val.raw) == true, "NEG_INF must be NegInf"); // 4. 测试 NaN(指数全为1,尾数不为0) val.raw = C_FLOAT_EXP_MASK | 0x00000001U; // 制造一个 NaN ASSERT_MSG(c_Float_IsNAN(val.raw) == 1, "Should be recognized as NaN"); val.raw = C_FLOAT_POS_INF; // 无穷大的尾数是0,不属于 NaN ASSERT_MSG(c_Float_IsNAN(val.raw) == 0, "Infinity is NOT NaN"); } // 用例 2:测试 Float 基础数学四则运算(数值运算准确性) void test_float_math_operations() { c_Float_t res, out_add, out_sub, out_mul, out_div; c_Float_t a, b; a.f = 5.5f; b.f = 2.25f; // 1. 加法测试 5.5 + 2.25 = 7.75 out_add.raw = c_Float_Add(a.raw, b.raw); res.f = 7.75f; ASSERT_INT_EQ_MSG(res.raw, out_add.raw, "Soft-Float Add failed (5.5 + 2.25)"); // 2. 减法测试 5.5 - 2.25 = 3.25 out_sub.raw = c_Float_Sub(a.raw, b.raw); res.f = 3.25f; ASSERT_INT_EQ_MSG(res.raw, out_sub.raw, "Soft-Float Sub failed (5.5 - 2.25)"); // 3. 乘法测试 5.5 * 2.25 = 12.375 out_mul.raw = c_Float_Mul(a.raw, b.raw); res.f = 12.375f; ASSERT_INT_EQ_MSG(res.raw, out_mul.raw, "Soft-Float Mul failed (5.5 * 2.25)"); // 4. 除法测试 5.5 / 2.25 = 2.444444... (通过联合体转换进行交叉对比) out_div.raw = c_Float_Div(a.raw, b.raw); float expected_div = 5.5f / 2.25f; uint32_t expected_raw = ((c_Float_t){.f = expected_div}).raw; // 经过软除法精度升级后,这里预期可以做到每一个二进制位都完全绝对对齐(0 ULP 误差) ASSERT_INT_EQ_MSG((int)expected_raw, (int)out_div.raw, "Soft-Float Div Round-to-Nearest-Even failed to align with hardware bits"); } void test_float_div_complete() { c_Float_t a, b, out; // ------------------------------------------------------------- // 测试 1:常规数值除法 (15.5 / 2.0 = 7.75) // ------------------------------------------------------------- a.f = 15.5f; b.f = 2.0f; out.raw = c_Float_Div(a.raw, b.raw); ASSERT_MSG(fabsf(7.75f - out.f) b 返回正数 a.d = 100.5; b.d = 200.5; ASSERT_MSG(c_Double_Cmp(a.raw, b.raw) < 0, "100.5 should be less than 200.5"); ASSERT_MSG(c_Double_Cmp(b.raw, a.raw) > 0, "200.5 should be greater than 100.5"); ASSERT_MSG(c_Double_Cmp(a.raw, a.raw) == 0, "100.5 should be equal to itself"); // 3. 原生内联函数的包装测试 (c_double_cmp) ASSERT_MSG(c_double_cmp(10.0, 20.0) < 0, "Inline double compare wrapper failed"); } void test_float_isnan_pure_bits() { // 场景 1:制造标准常规数值(如 1.0f)—— 预期:非 NaN (0) // 符号=0, 指数=127, 尾数=0 uint32_t normal_num = c_Float_Pack(0, 127, 0); ASSERT_INT_EQ_MSG(0, c_Float_IsNAN(normal_num), "Normal number 1.0f must NOT be NaN"); // 场景 2:正无穷大 (C_FLOAT_POS_INF) —— 预期:非 NaN (0) // 它的指数全为 1,但尾数严格为 0 ASSERT_INT_EQ_MSG(0, c_Float_IsNAN(C_FLOAT_POS_INF), "Positive Infinity must NOT be NaN"); ASSERT_INT_EQ_MSG(0, c_Float_IsNAN(C_FLOAT_NEG_INF), "Negative Infinity must NOT be NaN"); // 场景 3:制造一个最微小的 Quiet NaN (QNaN) —— 预期:是 NaN (1) // 指数全为 1 (0xFF),尾数最高位为 1 (0x400000) uint32_t qnan_bits = c_Float_Pack(0, 0xFF, 0x400000U); ASSERT_MSG(c_Float_IsNAN(qnan_bits), "Quiet NaN bits must be recognized as NaN"); // 场景 4:制造一个最微小的 Signaling NaN (SNaN) —— 预期:是 NaN (1) // 指数全为 1 (0xFF),尾数最低位为 1 (0x000001) uint32_t snan_bits = c_Float_Pack(0, 0xFF, 0x000001U); ASSERT_MSG(c_Float_IsNAN(snan_bits), "Signaling NaN bits must be recognized as NaN"); // 场景 5:测试带有符号位的 NaN (负 NaN) —— 预期:是 NaN (1) // IEEE 754 规范中,NaN 的符号位不影响它是 NaN 的事实 uint32_t neg_nan_bits = c_Float_Pack(1, 0xFF, 0x7FFFFFU); ASSERT_MSG(c_Float_IsNAN(neg_nan_bits), "Negative NaN bits must also be recognized as NaN"); } void test_float_inf_plus_neginf() { // 1. 获取正无穷大与负无穷大的位表示 uint32_t pos_inf = C_FLOAT_POS_INF; // 0x7F800000 uint32_t neg_inf = C_FLOAT_NEG_INF; // 0xFF800000 // 2. 执行待测的软浮点加法:(+Inf) + (-Inf) uint32_t result_raw = c_Float_Add(pos_inf, neg_inf); // 3. 核心断言:结果必须是 NaN // 使用 c_Float_IsNAN 验证其特征是否为:指数全 1,尾数非 0 ASSERT_MSG(c_Float_IsNAN(result_raw), "IEEE 754 standard: (+Inf) + (-Inf) must produce NaN"); // 4. 反向验证:它绝对不能再被误判为任何形式的无穷大或零 ASSERT_MSG(!c_Float_IsInf(result_raw), "Result NaN must not be classified as Infinity"); ASSERT_MSG(!c_Float_IsZero(result_raw), "Result NaN must not be classified as Zero"); // 5. 跨双精度对称验证:(+Inf) + (-Inf) 同样适用于 64 位双精度 uint64_t d_pos_inf = C_DOUBLE_POS_INF; uint64_t d_neg_inf = C_DOUBLE_NEG_INF; uint64_t d_result_raw = c_Double_Add(d_pos_inf, d_neg_inf); ASSERT_MSG(c_Double_IsNAN(d_result_raw), "IEEE 754 standard: Double (+Inf) + (-Inf) must produce NaN"); } void test_double_mul_and_div_complete() { c_Double_t da, db, dout; // ----------------------------------------------------------------- // 测试 1:验证跨 64 位大整数相乘的精确偶数舍入 // ----------------------------------------------------------------- da.d = 1.23456789012345; db.d = -9.87654321098765; dout.raw = c_Double_Mul(da.raw, db.raw); double expected_mul = 1.23456789012345 * -9.87654321098765; c_Double_t native_mul = {.d = expected_mul}; // 【终极断言升级】:杜绝 int 转换截断,对双精度 64 位全局原始编码进行无差错硬核对齐 ASSERT_MSG(native_mul.raw == dout.raw, "c_Double_Mul 64-bit full-width precision failed to align with hardware FPU"); // ----------------------------------------------------------------- // 测试 2:验证双精度无限循环小数除法的长窗口状态机精度 // ----------------------------------------------------------------- da.d = 1.0; db.d = 3.0; // 1.0 / 3.0 dout.raw = c_Double_Div(da.raw, db.raw); double expected_div = 1.0 / 3.0; c_Double_t native_div = {.d = expected_div}; ASSERT_INT_EQ_MSG((int)native_div.parts.fraction, (int)dout.parts.fraction, "c_Double_Div bit-level precision error at 1.0/3.0"); // ----------------------------------------------------------------- // 测试 3:验证双精度 0.0 与 无穷大的复合熔断边界 // ----------------------------------------------------------------- // 边界 A:0.0 * Inf -> 必须返回 NaN uint64_t zero_mul_inf = c_Double_Mul(to_raw64(0.0), C_DOUBLE_POS_INF); ASSERT_MSG(c_Double_IsNAN(zero_mul_inf), "Double 0.0 * +Inf must result in NaN"); // 边界 B:0.0 / 0.0 -> 必须返回 NaN uint64_t zero_div_zero = c_Double_Div(to_raw64(0.0), to_raw64(-0.0)); ASSERT_MSG(c_Double_IsNAN(zero_div_zero), "Double 0.0 / -0.0 must result in NaN"); // 边界 C:常规有限双精度数除以 0.0 -> 产生无穷大 da.d = -55.5; uint64_t div_zero = c_Double_Div(to_raw64(da.d), to_raw64(0.0)); ASSERT_MSG(c_Double_IsNegInf(div_zero), "Negative double divided by 0.0 must result in -Inf"); } void test_double_add_complete() { c_Double_t da, db, dout; // ----------------------------------------------------------------- // 测试 1:常规双精度数值加减(50.25 + 25.5 = 75.75) // ----------------------------------------------------------------- da.d = 50.25; db.d = 25.5; dout.raw = c_Double_Add(da.raw, db.raw); // 使用真值进行精度验证 ASSERT_MSG(fabs(dout.d - 75.75) < 1e-9, "Regular Double Add numerical verification failed"); // ----------------------------------------------------------------- // 测试 2:验证正负无穷大冲抵边界熔断(+Inf + -Inf = NaN) // ----------------------------------------------------------------- uint64_t res_nan = c_Double_Add(C_DOUBLE_POS_INF, C_DOUBLE_NEG_INF); ASSERT_MSG(c_Double_IsNAN(res_nan), "IEEE 754: Double (+Inf) + (-Inf) must produce NaN"); // ----------------------------------------------------------------- // 测试 3:验证异号数值完全抵消(5.5 + -5.5 = +0.0) // ----------------------------------------------------------------- da.d = 5.5; db.d = -5.5; dout.raw = c_Double_Add(da.raw, db.raw); // 验证返回的是否是干净的、符号位为0的正零 (0x0000000000000000) ASSERT_INT_EQ_MSG(0, (int)dout.raw, "Opposite numbers sum must strictly result in +0.0 bits"); // ----------------------------------------------------------------- // 测试 4:大跨度对阶精度测试(1.0 + 1e-17 触发全移出边界) // ----------------------------------------------------------------- da.d = 1.0; db.d = 1e-17; // 这个值太小了,在双精度 53 位尾数对阶时会被完全移出去,但会触发 sticky 位置 1 dout.raw = c_Double_Add(da.raw, db.raw); // 按照偶数舍入规则,sticky=1,GRS=001 <= 4,将被舍去,结果应该严格保持为 1.0 ASSERT_MSG(dout.d == 1.0, "Large exponent gap shift processing failed"); // ----------------------------------------------------------------- // 测试 5:向最近偶数舍入的 0 ULP 硬件级绝对对齐校验 // ----------------------------------------------------------------- da.d = 1.23456789012345; db.d = 9.87654321098765; dout.raw = c_Double_Add(da.raw, db.raw); double native_expected = 1.23456789012345 + 9.87654321098765; c_Double_t native_val = {.d = native_expected}; // 通过对比尾数域,验证是否做到了 100% 硬件位对齐 ASSERT_INT_EQ_MSG((int)native_val.parts.fraction, (int)dout.parts.fraction, "Soft-Double Add failed to align with hardware FPU bits"); } int main(int argc, char** argv){ TEST_START(Starting Unit Tests); // 运行需要内存环境的用例 RUN_TEST(test_float_classification_and_pack); RUN_TEST(test_float_math_operations); RUN_TEST(test_float_edge_cases); RUN_TEST(test_double_operations_and_compare); RUN_TEST(test_float_isnan_pure_bits); RUN_TEST(test_float_inf_plus_neginf); RUN_TEST(test_float_div_complete); RUN_TEST(test_double_mul_and_div_complete); RUN_TEST(test_double_add_complete); // 打印最终统计报告 TEST_REPORT(); RETURN_TEST_STATUS; }