| // SPDX-FileCopyrightText: The Eigen Authors |
| // SPDX-License-Identifier: MPL-2.0 |
| |
| #include "main.h" |
| #include "twoprod_helpers.h" |
| |
| template <typename Scalar, typename Packet> |
| void check_doubleword_product(const Scalar (&data)[7]) { |
| constexpr Index size = internal::unpacket_traits<Packet>::size; |
| EIGEN_ALIGN_MAX Scalar hi[size], lo[size]; |
| const Scalar epsilon = NumTraits<Scalar>::epsilon(); |
| const Scalar bound = Scalar(1.25) * epsilon * epsilon * numext::abs(data[4]); // 5*u^2, u = eps/2. |
| for (int exponent : {-20, 0, 20}) { |
| // Keep the operands runtime so constant folding cannot replace the arithmetic under test. |
| volatile Scalar x_scale = numext::ldexp(Scalar(1), exponent), y_scale = numext::ldexp(Scalar(1), -exponent); |
| for (int sign : {-1, 1}) { |
| const Scalar x_hi = Scalar(sign) * data[0] * x_scale; |
| const Scalar x_lo = Scalar(sign) * data[1] * x_scale; |
| const Scalar y_hi = data[2] * y_scale; |
| const Scalar y_lo = data[3] * y_scale; |
| VERIFY_IS_EQUAL(x_hi + x_lo, x_hi); |
| VERIFY_IS_EQUAL(y_hi + y_lo, y_hi); |
| Packet p_hi, p_lo; |
| internal::twoprod(internal::pset1<Packet>(x_hi), internal::pset1<Packet>(x_lo), internal::pset1<Packet>(y_hi), |
| internal::pset1<Packet>(y_lo), p_hi, p_lo); |
| internal::pstore(hi, p_hi); |
| internal::pstore(lo, p_lo); |
| for (Index i = 0; i < size; ++i) { |
| VERIFY_IS_EQUAL(hi[i], Scalar(sign) * data[4]); |
| const Scalar error = numext::abs((lo[i] - Scalar(sign) * data[5]) - Scalar(sign) * data[6]); |
| VERIFY(error < bound); |
| } |
| } |
| } |
| } |
| |
| EIGEN_DECLARE_TEST(twoprod) { |
| using FloatPacket = internal::packet_traits<float>::type; |
| using DoublePacket = internal::packet_traits<double>::type; |
| check_twoprod_packet<float>(); |
| check_twoprod_packet<double>(); |
| check_twoprod_packet<FloatPacket>(); |
| check_twoprod_packet<DoublePacket>(); |
| |
| // {x_hi, x_lo, y_hi, y_lo, ref_hi, ref_lo, ref_tail}. The reference product is |
| // decomposed with 600-bit MPFR, rounding each word to the tested scalar type. |
| // These normalized inputs exceed the former 2*u^2 bound in both precisions. |
| const float float_data[] = {1.1675887107849121f, -3.9186936362511915e-08f, 1.7997856140136719f, |
| 5.2592689314678864e-08f, 2.1014094352722168f, -7.963821957446271e-08f, |
| 1.2973732602550997e-15f}; |
| const double double_data[] = {1.4946183601517316, 9.493375847471864e-17, 1.4603476327002127, |
| -8.3856771222625945e-17, 2.182662384037855, 1.9088477361435543e-16, |
| -3.7615759087187478e-33}; |
| check_doubleword_product<float, float>(float_data); |
| check_doubleword_product<double, double>(double_data); |
| check_doubleword_product<float, FloatPacket>(float_data); |
| check_doubleword_product<double, DoublePacket>(double_data); |
| } |