fix(hex8): bridge nonfinite vector sums before error arithmetic
This commit is contained in:
@@ -496,6 +496,7 @@ fesa::hex8_internal::GeometryPacketInput GeometryDyadicFixture() {
|
||||
// Selected observation reuses the weighted pair but retains each checked Add.
|
||||
void ExpectGeometryPacketBitsAndFlags(
|
||||
const fesa::hex8_internal::GeometryPacketInput& input, bool prior_status) {
|
||||
SCOPED_TRACE(prior_status);
|
||||
std::fenv_t original;
|
||||
ASSERT_EQ(std::fegetenv(&original), 0);
|
||||
const auto original_csr = _mm_getcsr();
|
||||
@@ -649,6 +650,7 @@ TEST(Hex8HighLow, GeometryPacketPreservesOrderedOverflowAndPreparedInvalid) {
|
||||
const double maximum = std::numeric_limits<double>::max();
|
||||
std::size_t checks = 0;
|
||||
for (bool overflow_order : {false, true}) {
|
||||
SCOPED_TRACE(overflow_order);
|
||||
fesa::hex8_internal::GeometryPacketInput input{};
|
||||
input.weight = {0.5, 0};
|
||||
for (std::size_t l = 0; l < 3; ++l)
|
||||
@@ -672,6 +674,69 @@ TEST(Hex8HighLow, GeometryPacketPreservesOrderedOverflowAndPreparedInvalid) {
|
||||
checks += 2;
|
||||
RecordProperty("avx2_geometry_ordered_invalid_checks", static_cast<int>(checks));
|
||||
}
|
||||
|
||||
TEST(Hex8HighLow, GeometryPacketSumFallbackPreservesNearMaxAndSubnormalStatus) {
|
||||
if (fesa::hex8_internal::SelectMaterialPacketEvaluator() ==
|
||||
fesa::hex8_internal::EvaluateMaterialPacketScalar)
|
||||
GTEST_SKIP() << "Geometry AVX2 masked environment is not selected.";
|
||||
const double maximum = std::numeric_limits<double>::max();
|
||||
const double normal = std::ldexp(1.0, -1022);
|
||||
const double tiny = std::ldexp(1.0, -1074);
|
||||
const double quarter = std::ldexp(1.0, 969);
|
||||
std::size_t checks = 0;
|
||||
for (double tail : {0.0, normal, tiny})
|
||||
for (std::size_t bad = 0; bad < 4; ++bad) {
|
||||
SCOPED_TRACE(tail);
|
||||
SCOPED_TRACE(bad);
|
||||
fesa::hex8_internal::GeometryPacketInput input{};
|
||||
input.weight = {0.5, 0};
|
||||
// Both pairs are normalized. Head sum is finite; middle contributes
|
||||
// 2^970 and the joined sum overflows. Other lanes retain finite values.
|
||||
input.gradient_stress[0][0] = {maximum, quarter};
|
||||
input.gradient_stress[0][1] = {quarter, tail};
|
||||
for (std::size_t lane = 0; lane < 4; ++lane) {
|
||||
const double scale = lane == bad ? 1.0 : 0.5;
|
||||
input.gradient_b[0].values[lane] = {scale, 0};
|
||||
input.gradient_b[1].values[lane] = {scale, 0};
|
||||
input.gradient_b[2].values[lane] = {1, 0};
|
||||
}
|
||||
ExpectGeometryPacketBitsAndFlags(input, false);
|
||||
ExpectGeometryPacketBitsAndFlags(input, true);
|
||||
checks += 2;
|
||||
}
|
||||
fesa::hex8_internal::GeometryPacketInput finite{};
|
||||
finite.weight = {1, 0};
|
||||
finite.gradient_stress[0][0] = {normal, 0};
|
||||
finite.gradient_stress[0][1] = {normal + tiny, 0};
|
||||
for (std::size_t lane = 0; lane < 4; ++lane) {
|
||||
finite.gradient_b[0].values[lane] = {1, 0};
|
||||
finite.gradient_b[1].values[lane] = {1, 0};
|
||||
}
|
||||
// TwoSum(N,N+d) has finite normal inputs and a subnormal error d.
|
||||
ExpectGeometryPacketBitsAndFlags(finite, false);
|
||||
ExpectGeometryPacketBitsAndFlags(finite, true);
|
||||
checks += 2;
|
||||
// Mixed prefix: finite subnormal-error lanes run before another lane's head
|
||||
// overflow. The bridge must preserve the whole packet's status union.
|
||||
for (std::size_t bad = 0; bad < 4; ++bad) {
|
||||
SCOPED_TRACE(bad);
|
||||
fesa::hex8_internal::GeometryPacketInput mixed{};
|
||||
mixed.weight = {1, 0};
|
||||
mixed.gradient_stress[0][2] = {normal, 0};
|
||||
mixed.gradient_stress[1][2] = {normal + tiny, 0};
|
||||
mixed.gradient_stress[2][0] = {maximum, 0};
|
||||
mixed.gradient_stress[2][1] = {maximum, 0};
|
||||
for (std::size_t lane = 0; lane < 4; ++lane) {
|
||||
mixed.gradient_b[0].values[lane] = {lane == bad ? 1.0 : 0.0, 0};
|
||||
mixed.gradient_b[1].values[lane] = {lane == bad ? 1.0 : 0.0, 0};
|
||||
mixed.gradient_b[2].values[lane] = {lane == bad ? 0.0 : 1.0, 0};
|
||||
}
|
||||
ExpectGeometryPacketBitsAndFlags(mixed, false);
|
||||
ExpectGeometryPacketBitsAndFlags(mixed, true);
|
||||
checks += 2;
|
||||
}
|
||||
RecordProperty("avx2_geometry_sum_fallback_checks", static_cast<int>(checks));
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(Hex8HighLow, PacketBackendSelectionRecoversAfterEnvironmentRestoration) {
|
||||
|
||||
Reference in New Issue
Block a user