| 239 | |
| 240 | template <typename Base, typename Exponent> |
| 241 | void float_pow_test_impl() { |
| 242 | const Base tol = test_precision<Base>(); |
| 243 | std::vector<Base> abs_base_vals = special_values<Base>(); |
| 244 | std::vector<Exponent> abs_exponent_vals = special_values<Exponent>(); |
| 245 | for (int i = 0; i < 100; i++) { |
| 246 | abs_base_vals.push_back(internal::random<Base>(Base(0), Base(10))); |
| 247 | abs_exponent_vals.push_back(internal::random<Exponent>(Exponent(0), Exponent(10))); |
| 248 | } |
| 249 | const Index num_repeats = internal::packet_traits<Base>::size + 1; |
| 250 | ArrayX<Base> bases(num_repeats), eigenPow(num_repeats); |
| 251 | bool all_pass = true; |
| 252 | for (Base abs_base : abs_base_vals) |
| 253 | for (Base base : {negative_or_zero(abs_base), abs_base}) { |
| 254 | bases.setConstant(base); |
| 255 | for (Exponent abs_exponent : abs_exponent_vals) { |
| 256 | for (Exponent exponent : {negative_or_zero(abs_exponent), abs_exponent}) { |
| 257 | eigenPow = bases.pow(exponent); |
| 258 | for (Index j = 0; j < num_repeats; j++) { |
| 259 | Base e = ref_pow<Base, Exponent>::run(bases(j), exponent); |
| 260 | if (is_integer(exponent)) { |
| 261 | // std::pow may return an incorrect result for a very large integral exponent |
| 262 | // if base is negative and the exponent is odd, then the result must be negative |
| 263 | // if std::pow returns otherwise, flip the sign |
| 264 | bool exp_is_odd = is_odd(exponent); |
| 265 | bool base_is_neg = !(numext::isnan)(base) && (bool)numext::signbit(base); |
| 266 | bool result_is_neg = exp_is_odd && base_is_neg; |
| 267 | bool ref_is_neg = !(numext::isnan)(e) && (bool)numext::signbit(e); |
| 268 | bool flip_sign = result_is_neg != ref_is_neg; |
| 269 | if (flip_sign) e = -e; |
| 270 | } |
| 271 | |
| 272 | Base a = eigenPow(j); |
| 273 | #ifdef EIGEN_COMP_MSVC |
| 274 | // Work around MSVC return value on underflow. |
| 275 | // if std::pow returns 0 and Eigen returns a denormalized value, then skip the test |
| 276 | int eigen_fpclass = std::fpclassify(a); |
| 277 | if (e == Base(0) && eigen_fpclass == FP_SUBNORMAL) continue; |
| 278 | #endif |
| 279 | |
| 280 | #ifdef EIGEN_VECTORIZE_NEON |
| 281 | // Work around NEON flush-to-zero mode |
| 282 | // if std::pow returns denormalized value and Eigen returns 0, then skip the test |
| 283 | int ref_fpclass = std::fpclassify(e); |
| 284 | if (a == Base(0) && ref_fpclass == FP_SUBNORMAL) continue; |
| 285 | #endif |
| 286 | |
| 287 | bool both_nan = (numext::isnan)(a) && (numext::isnan)(e); |
| 288 | bool exact_or_approx = (a == e) || internal::isApprox(a, e, tol); |
| 289 | bool same_sign = (bool)numext::signbit(e) == (bool)numext::signbit(a); |
| 290 | bool success = both_nan || (exact_or_approx && same_sign); |
| 291 | all_pass &= success; |
| 292 | if (!success) { |
| 293 | std::cout << "pow(" << bases(j) << "," << exponent << ") = " << a << " != " << e << std::endl; |
| 294 | } |
| 295 | } |
| 296 | } |
| 297 | } |
| 298 | } |
nothing calls this directly
no test coverage detected