Fix arm32 float division and related bugs

This commit is contained in:
Charles Schlosser
2023-08-29 00:36:07 +00:00
committed by Rasmus Munk Larsen
parent 2873916f1c
commit 81b48065ea
4 changed files with 115 additions and 82 deletions

View File

@@ -47,7 +47,7 @@ std::vector<Scalar> special_values() {
const Scalar sqrt2 = Scalar(std::sqrt(2));
const Scalar inf = Eigen::NumTraits<Scalar>::infinity();
const Scalar nan = Eigen::NumTraits<Scalar>::quiet_NaN();
const Scalar denorm_min = std::numeric_limits<Scalar>::denorm_min();
const Scalar denorm_min = EIGEN_ARCH_ARM ? zero : std::numeric_limits<Scalar>::denorm_min();
const Scalar min = (std::numeric_limits<Scalar>::min)();
const Scalar max = (std::numeric_limits<Scalar>::max)();
const Scalar max_exp = (static_cast<Scalar>(int(Eigen::NumTraits<Scalar>::max_exponent())) * Scalar(EIGEN_LN2)) / eps;
@@ -97,6 +97,12 @@ void binary_op_test(std::string name, Fn fun, RefFn ref) {
for (Index j = 0; j < lhs.cols(); ++j) {
Scalar e = static_cast<Scalar>(ref(lhs(i,j), rhs(i,j)));
Scalar a = actual(i, j);
#if EIGEN_ARCH_ARM
// Work around NEON flush-to-zero mode
// if ref returns denormalized value and Eigen returns 0, then skip the test
int ref_fpclass = std::fpclassify(e);
if (a == Scalar(0) && ref_fpclass == FP_SUBNORMAL) continue;
#endif
bool success = (a==e) || ((numext::isfinite)(e) && internal::isApprox(a, e, tol)) || ((numext::isnan)(a) && (numext::isnan)(e));
if ((a == a) && (e == e)) success &= (bool)numext::signbit(e) == (bool)numext::signbit(a);
all_pass &= success;
@@ -767,7 +773,12 @@ template<typename ArrayType> void array_real(const ArrayType& m)
m3(rows, cols),
m4 = m1;
m4 = (m4.abs()==Scalar(0)).select(Scalar(1),m4);
// avoid denormalized values so verification doesn't fail on platforms that don't support them
// denormalized behavior is tested elsewhere (unary_op_test, binary_ops_test)
const Scalar min = (std::numeric_limits<Scalar>::min)();
m1 = (m1.abs()<min).select(Scalar(0),m1);
m2 = (m2.abs()<min).select(Scalar(0),m2);
m4 = (m4.abs()<min).select(Scalar(1),m4);
Scalar s1 = internal::random<Scalar>();
@@ -808,6 +819,7 @@ template<typename ArrayType> void array_real(const ArrayType& m)
// avoid inf and NaNs so verification doesn't fail
m3 = m4.abs();
VERIFY_IS_APPROX(m3.sqrt(), sqrt(abs(m3)));
VERIFY_IS_APPROX(m3.rsqrt(), Scalar(1)/sqrt(abs(m3)));
VERIFY_IS_APPROX(rsqrt(m3), Scalar(1)/sqrt(abs(m3)));

View File

@@ -754,7 +754,7 @@ void packetmath_test_IEEE_corner_cases(const RefFunctorT& ref_fun,
}
// Test for subnormals.
if (Cond && std::numeric_limits<Scalar>::has_denorm == std::denorm_present) {
if (Cond && std::numeric_limits<Scalar>::has_denorm == std::denorm_present && !EIGEN_ARCH_ARM) {
for (int scale = 1; scale < 5; ++scale) {
// When EIGEN_FAST_MATH is 1 we relax the conditions slightly, and allow the function
@@ -912,12 +912,14 @@ void packetmath_real() {
CHECK_CWISE1_BYREF1_IF(PacketTraits::HasExp, REF_FREXP, internal::pfrexp);
if (PacketTraits::HasExp) {
// Check denormals:
#if !EIGEN_ARCH_ARM
for (int j=0; j<3; ++j) {
data1[0] = Scalar(std::ldexp(1, NumTraits<Scalar>::min_exponent()-j));
CHECK_CWISE1_BYREF1_IF(PacketTraits::HasExp, REF_FREXP, internal::pfrexp);
data1[0] = -data1[0];
CHECK_CWISE1_BYREF1_IF(PacketTraits::HasExp, REF_FREXP, internal::pfrexp);
}
#endif
// zero
data1[0] = Scalar(0);

View File

@@ -113,25 +113,6 @@ template<int OtherStorage, typename SparseMatrixType> void sparse_permutations(c
res_d = p.inverse()*mat_d;
VERIFY(res.isApprox(res_d) && "inv(p)*mat");
// test non-plaintype expressions that require additional temporary
const Scalar alpha(2.34);
res_d = p * (alpha * mat_d);
VERIFY_TEMPORARY_COUNT( res = p * (alpha * mat), 2);
VERIFY( res.isApprox(res_d) && "p*(alpha*mat)" );
res_d = (alpha * mat_d) * p;
VERIFY_TEMPORARY_COUNT( res = (alpha * mat) * p, 2);
VERIFY( res.isApprox(res_d) && "(alpha*mat)*p" );
res_d = p.inverse() * (alpha * mat_d);
VERIFY_TEMPORARY_COUNT( res = p.inverse() * (alpha * mat), 2);
VERIFY( res.isApprox(res_d) && "inv(p)*(alpha*mat)" );
res_d = (alpha * mat_d) * p.inverse();
VERIFY_TEMPORARY_COUNT( res = (alpha * mat) * p.inverse(), 2);
VERIFY( res.isApprox(res_d) && "(alpha*mat)*inv(p)" );
//
VERIFY( is_sorted( (p * mat * p.inverse()).eval() ));