2026-08-29 00:53:40 +08:00
|
|
|
|
#include "c_float.h"
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
#include <stdio.h>
|
2026-08-29 11:39:28 +08:00
|
|
|
|
#include <c_Test.h>
|
2026-08-29 00:53:40 +08:00
|
|
|
|
|
2026-08-29 11:39:28 +08:00
|
|
|
|
/* ------------------------------------------------------------------------------------------------------------------ */
|
|
|
|
|
|
/* */
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @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)<FLT_EPSILON, "Regular division failed (15.5 / 2.0)");
|
|
|
|
|
|
|
|
|
|
|
|
// -------------------------------------------------------------
|
|
|
|
|
|
// 测试 2:符号位正确结合测试 (-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) < FLT_EPSILON, "Signed division failed (-15.5 / 2.0)");
|
|
|
|
|
|
|
|
|
|
|
|
// -------------------------------------------------------------
|
|
|
|
|
|
// 测试 3:有限数除以 0.0 —— 预期触发 ±Inf 拦截 (X / 0 = Inf)
|
|
|
|
|
|
// -------------------------------------------------------------
|
|
|
|
|
|
a.f = 5.25f;
|
|
|
|
|
|
b.f = 0.0f;
|
|
|
|
|
|
out.raw = c_Float_Div(a.raw, b.raw);
|
|
|
|
|
|
ASSERT_MSG(c_Float_IsPosInf(out.raw), "5.25 / 0.0 must yield Positive Infinity");
|
|
|
|
|
|
|
|
|
|
|
|
a.f = -5.25f;
|
|
|
|
|
|
b.f = 0.0f;
|
|
|
|
|
|
out.raw = c_Float_Div(a.raw, b.raw);
|
|
|
|
|
|
ASSERT_MSG(c_Float_IsNegInf(out.raw), "-5.25 / 0.0 must yield Negative Infinity");
|
|
|
|
|
|
|
|
|
|
|
|
// -------------------------------------------------------------
|
|
|
|
|
|
// 测试 4:零除以零 边界熔断 —— 预期触发 NaN (0.0 / 0.0 = NaN)
|
|
|
|
|
|
// -------------------------------------------------------------
|
|
|
|
|
|
a.f = 0.0f;
|
|
|
|
|
|
b.f = 0.0f;
|
|
|
|
|
|
out.raw = c_Float_Div(a.raw, b.raw);
|
|
|
|
|
|
ASSERT_MSG(c_Float_IsNAN(out.raw), "0.0 / 0.0 must result in NaN");
|
|
|
|
|
|
|
|
|
|
|
|
// -------------------------------------------------------------
|
|
|
|
|
|
// 测试 5:无穷大除以无穷大 边界熔断 —— 预期触发 NaN (Inf / Inf = NaN)
|
|
|
|
|
|
// -------------------------------------------------------------
|
|
|
|
|
|
out.raw = c_Float_Div(C_FLOAT_POS_INF, C_FLOAT_POS_INF);
|
|
|
|
|
|
ASSERT_MSG(c_Float_IsNAN(out.raw), "PosInf / PosInf must result in NaN");
|
|
|
|
|
|
|
|
|
|
|
|
out.raw = c_Float_Div(C_FLOAT_POS_INF, C_FLOAT_NEG_INF);
|
|
|
|
|
|
ASSERT_MSG(c_Float_IsNAN(out.raw), "PosInf / NegInf must result in NaN");
|
|
|
|
|
|
|
|
|
|
|
|
// -------------------------------------------------------------
|
|
|
|
|
|
// 测试 6:精确偶数舍入测试(循环除法产生除不尽的无限循环小数)
|
|
|
|
|
|
// -------------------------------------------------------------
|
|
|
|
|
|
a.f = 1.0f;
|
|
|
|
|
|
b.f = 3.0f; // 1.0 / 3.0 = 0.33333333...
|
|
|
|
|
|
out.raw = c_Float_Div(a.raw, b.raw);
|
|
|
|
|
|
|
|
|
|
|
|
// 提取系统原生结果进行高精密比对(ULP 误差必须为 0)
|
|
|
|
|
|
float native_expected = 1.0f / 3.0f;
|
|
|
|
|
|
c_Float_t native_val = {.f = native_expected};
|
|
|
|
|
|
ASSERT_INT_EQ_MSG((int)native_val.raw, (int)out.raw, "1.0 / 3.0 Round-to-Nearest-Even failed");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 用例 3:测试 Float IEEE 754 软加法器/乘法器的特殊边界极限(这最容易导致软浮点数崩溃或死循环)
|
|
|
|
|
|
void test_float_edge_cases() {
|
|
|
|
|
|
c_Float_t a, b, out;
|
|
|
|
|
|
|
|
|
|
|
|
// 1. 任何数与 NaN 运算都必须得到 NaN
|
|
|
|
|
|
a.raw = C_FLOAT_EXP_MASK | 0x1234U; // NaN
|
|
|
|
|
|
b.f = 5.0f;
|
|
|
|
|
|
out.raw = c_Float_Add(a.raw, b.raw);
|
|
|
|
|
|
ASSERT_MSG(c_Float_IsNAN(out.raw) == 1, "NaN + Number must result in NaN");
|
|
|
|
|
|
|
|
|
|
|
|
// 2. 边界:正无穷大 + 负无穷大 应该得到 NaN (Inf - Inf = NaN)
|
|
|
|
|
|
out.raw = c_Float_Add(C_FLOAT_POS_INF, C_FLOAT_NEG_INF);
|
|
|
|
|
|
ASSERT_MSG(c_Float_IsNAN(out.raw), "PosInf + NegInf must result in NaN");
|
|
|
|
|
|
|
|
|
|
|
|
// 3. 边界:有限非零数除以 0 应该触发除零异常得到 无穷大 (X / 0 = Inf)
|
|
|
|
|
|
a.f = 3.5f;
|
|
|
|
|
|
b.f = 0.0f;
|
|
|
|
|
|
out.raw = c_Float_Div(a.raw, b.raw);
|
|
|
|
|
|
ASSERT_MSG(c_Float_IsPosInf(out.raw), "3.5 / 0.0 must result in Positive Infinity");
|
|
|
|
|
|
|
|
|
|
|
|
// 4. 边界:0 / 0 应该产生 NaN
|
|
|
|
|
|
a.f = 0.0f;
|
|
|
|
|
|
b.f = 0.0f;
|
|
|
|
|
|
out.raw = c_Float_Div(a.raw, b.raw);
|
|
|
|
|
|
ASSERT_MSG(c_Float_IsNAN(out.raw) == 1, "0.0 / 0.0 must result in NaN");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 用例 4:测试 Double 的数值运算及大小比较行为 (c_Double_Cmp)
|
|
|
|
|
|
void test_double_operations_and_compare() {
|
|
|
|
|
|
c_Double_t a, b, out;
|
|
|
|
|
|
|
|
|
|
|
|
// 1. 测试基础双精度加法
|
|
|
|
|
|
a.d = 123456789.12345;
|
|
|
|
|
|
b.d = 987654321.98765;
|
|
|
|
|
|
out.raw = c_Double_Add(a.raw, b.raw);
|
|
|
|
|
|
|
|
|
|
|
|
c_Double_t expected;
|
|
|
|
|
|
expected.d = a.d + b.d;
|
|
|
|
|
|
int64_t diff = (int64_t)out.raw - (int64_t)expected.raw;
|
|
|
|
|
|
ASSERT_MSG(labs(diff) <= 1, "c_Double_Add precision verification mismatched");
|
|
|
|
|
|
|
|
|
|
|
|
// 2. 测试 c_Double_Cmp 逻辑
|
|
|
|
|
|
// 规定返回值规范:a < b 返回负数,a == b 返回 0,a > 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");
|
2026-08-29 00:53:40 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int main(int argc, char** argv){
|
2026-08-29 11:39:28 +08:00
|
|
|
|
TEST_START(Starting Unit Tests);
|
2026-08-29 00:53:40 +08:00
|
|
|
|
|
2026-08-29 11:39:28 +08:00
|
|
|
|
// 运行需要内存环境的用例
|
|
|
|
|
|
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;
|
2026-08-29 00:53:40 +08:00
|
|
|
|
}
|