Use scaled long-double quadratic arithmetic without explicit FMA. Validate entry candidates against backend geometry and localize uncertain entries along the original exterior trajectory. Preserve conservative miss semantics and propagate concrete entry failures. Add production-sample and numerical regression coverage.
66 lines
2.5 KiB
C
66 lines
2.5 KiB
C
/* Exercise the private numerical kernel directly, including coefficient
|
|
* ranges that cannot be represented by a public double worldtube fixture.
|
|
* The build rule omits the separately compiled asymptotic.c. */
|
|
#include "../src/asymptotic.c"
|
|
|
|
#include <stdio.h>
|
|
|
|
static int failures;
|
|
|
|
#define CHECK(condition, message) do { \
|
|
if (!(condition)) { \
|
|
fprintf(stderr, "FAIL %s:%d: %s\n", __FILE__, __LINE__, message); \
|
|
++failures; \
|
|
} \
|
|
} while (0)
|
|
|
|
static void check_scaled(int exponent) {
|
|
const long double scale = scalbnl(1.0L, exponent);
|
|
double root = -1.0;
|
|
EntryQuadratic k = {scale, -3.0L * scale, 2.0L * scale};
|
|
CHECK(entry_solve(&k, &root) == ENTRY_SOLVE_ENTRY && root == 1.0,
|
|
"common scale preserves smallest inward root");
|
|
k = (EntryQuadratic){scale, -scale, scale};
|
|
CHECK(entry_solve(&k, &root) == ENTRY_SOLVE_MISS,
|
|
"common scale preserves a clear miss");
|
|
k = (EntryQuadratic){0.0L, -scale, 2.0L * scale};
|
|
CHECK(entry_solve(&k, &root) == ENTRY_SOLVE_ENTRY && root == 2.0,
|
|
"common scale preserves linear entry");
|
|
k = (EntryQuadratic){scale, -scale, 0.0L};
|
|
CHECK(entry_solve(&k, &root) == ENTRY_SOLVE_ENTRY && root == 0.0,
|
|
"common scale preserves boundary entry");
|
|
k = (EntryQuadratic){-scale, scale, 2.0L * scale};
|
|
CHECK(entry_solve(&k, &root) == ENTRY_SOLVE_ENTRY && root == 2.0,
|
|
"common scale preserves concave entry");
|
|
}
|
|
|
|
static void test_product_cancellation(void) {
|
|
const long double u = scalbnl(1.0L, 1 - LDBL_MANT_DIG);
|
|
const EntryQuadratic k = {1.0L + u, -2.0L, 1.0L - 0.5L * u};
|
|
long double scale;
|
|
(void)entry_discriminant(&k, &scale);
|
|
/* Exact dyadic oracle: 4 - 4(1+u)(1-u/2) = -2u + 2u^2.
|
|
* A separately rounded 4*a*c is 4 and loses this nonzero discriminant. */
|
|
double root;
|
|
CHECK(entry_solve(&k, &root) == ENTRY_SOLVE_UNCERTAIN,
|
|
"product cancellation must remain uncertain, not a proven miss");
|
|
}
|
|
|
|
int main(void) {
|
|
check_scaled(0);
|
|
check_scaled(LDBL_MAX_EXP - 4);
|
|
check_scaled(LDBL_MIN_EXP + 4);
|
|
check_scaled(LDBL_MIN_EXP - LDBL_MANT_DIG + 2);
|
|
test_product_cancellation();
|
|
double root;
|
|
EntryQuadratic k = {LDBL_MIN, LDBL_MAX / 8.0L, 1.0L};
|
|
CHECK(entry_solve(&k, &root) == ENTRY_SOLVE_UNCERTAIN,
|
|
"scaling cannot silently erase a nonzero coefficient");
|
|
k = (EntryQuadratic){1.0L, 2.0L, -INFINITY};
|
|
CHECK(entry_solve(&k, &root) == ENTRY_SOLVE_UNCERTAIN,
|
|
"nonfinite coefficient is not a normal entry");
|
|
if (!failures)
|
|
puts("asymptotic quadratic regression passed");
|
|
return failures ? 1 : 0;
|
|
}
|