brintos

brintos / llvm-project-archived public Read only

0
0
Text · 9.2 KiB · db7b316 Raw
320 lines · plain
1//  (C) Copyright John Maddock 2006.2//  (C) Copyright Matt Borland 2024.3//  Use, modification and distribution are subject to the4//  Boost Software License, Version 1.0. (See accompanying file5//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)6 7#ifndef BOOST_MATH_TOOLS_TEST_HPP8#define BOOST_MATH_TOOLS_TEST_HPP9 10#ifdef _MSC_VER11#pragma once12#endif13 14#include <boost/math/tools/config.hpp>15#include <boost/math/tools/stats.hpp>16#include <boost/math/special_functions/fpclassify.hpp>17#include <boost/math/special_functions/relative_difference.hpp>18#include <boost/math/policies/error_handling.hpp>19#include <boost/test/test_tools.hpp>20#include <stdexcept>21#include <iostream>22#include <iomanip>23 24namespace boost{ namespace math{ namespace tools{25 26template <class T>27struct test_result28{29private:30   boost::math::tools::stats<T> stat;   // Statistics for the test.31   unsigned worst_case;                 // Index of the worst case test.32public:33   test_result() { worst_case = 0; }34   void set_worst(int i){ worst_case = i; }35   void add(const T& point){ stat.add(point); }36   // accessors:37   unsigned worst()const{ return worst_case; }38   T min BOOST_MATH_PREVENT_MACRO_SUBSTITUTION()const{ return (stat.min)(); }39   T max BOOST_MATH_PREVENT_MACRO_SUBSTITUTION()const{ return (stat.max)(); }40   T total()const{ return stat.total(); }41   T mean()const{ return stat.mean(); }42   std::uintmax_t count()const{ return stat.count(); }43   T variance()const{ return stat.variance(); }44   T variance1()const{ return stat.variance1(); }45   T rms()const{ return stat.rms(); }46 47   test_result& operator+=(const test_result& t)48   {49      if((t.stat.max)() > (stat.max)())50         worst_case = t.worst_case;51      stat += t.stat;52      return *this;53   }54};55 56template <class T>57struct calculate_result_type58{59   typedef typename T::value_type row_type;60   typedef typename row_type::value_type value_type;61};62 63template <class T>64T relative_error(T a, T b)65{66   return boost::math::relative_difference(a, b);67}68 69 70template <class T>71void set_output_precision(T, std::ostream& os)72{73#ifdef _MSC_VER74#pragma warning(push)75#pragma warning(disable:4127)76#endif77   if(std::numeric_limits<T>::digits10)78   {79      os << std::setprecision(std::numeric_limits<T>::digits10 + 2);80   }81   else82      os << std::setprecision(22); // and hope for the best!83 84#ifdef _MSC_VER85#pragma warning(pop)86#endif87}88 89template <class Seq>90void print_row(const Seq& row, std::ostream& os = std::cout)91{92   try {93      set_output_precision(row[0], os);94      for (unsigned i = 0; i < row.size(); ++i)95      {96         if (i)97            os << ", ";98         os << row[i];99      }100      os << std::endl;101   }102   catch (const std::exception&) {}103}104 105//106// Function test accepts an matrix of input values (probably a 2D std::array)107// and calls two functors for each row in the array - one calculates a value108// to test, and one extracts the expected value from the array (or possibly109// calculates it at high precision).  The two functors are usually simple lambda110// expressions.111//112template <class A, class F1, class F2>113test_result<typename calculate_result_type<A>::value_type> test(const A& a, F1 test_func, F2 expect_func)114{115   typedef typename A::value_type         row_type;116   typedef typename row_type::value_type  value_type;117 118   test_result<value_type> result;119 120   for(unsigned i = 0; i < a.size(); ++i)121   {122      const row_type& row = a[i];123      value_type point;124#ifndef BOOST_NO_EXCEPTIONS125      try126      {127#endif128         point = test_func(row);129#ifndef BOOST_NO_EXCEPTIONS130      }131      catch(const std::underflow_error&)132      {133         point = 0;134      }135      catch(const std::overflow_error&)136      {137         point = std::numeric_limits<value_type>::has_infinity ?138            std::numeric_limits<value_type>::infinity()139            : tools::max_value<value_type>();140      }141      catch(const std::exception& e)142      {143         std::cerr << e.what() << std::endl;144         print_row(row, std::cerr);145         BOOST_ERROR("Unexpected exception.");146         // so we don't get further errors:147         point = expect_func(row);148      }149#endif150      value_type expected = expect_func(row);151      value_type err = relative_error(point, expected);152#ifdef BOOST_INSTRUMENT153      if(err != 0)154      {155         std::cout << row[0] << " " << err;156         if(std::numeric_limits<value_type>::is_specialized)157         {158            std::cout << " (" << err / std::numeric_limits<value_type>::epsilon() << "eps)";159         }160         std::cout << std::endl;161      }162#endif163      if(!(boost::math::isfinite)(point) && (boost::math::isfinite)(expected))164      {165         std::cerr << "CAUTION: Found non-finite result, when a finite value was expected at entry " << i << "\n";166         std::cerr << "Found: " << point << " Expected " << expected << " Error: " << err << std::endl;167         print_row(row, std::cerr);168         BOOST_ERROR("Unexpected non-finite result");169      }170      if(err > 0.5f)171      {172         std::cerr << "CAUTION: Gross error found at entry " << i << ".\n";173         std::cerr << "Found: " << point << " Expected " << expected << " Error: " << err << std::endl;174         print_row(row, std::cerr);175         BOOST_ERROR("Gross error");176      }177      result.add(err);178      if((result.max)() == err)179         result.set_worst(i);180   }181   return result;182}183 184template <class Real, class A, class F1, class F2>185test_result<Real> test_hetero(const A& a, F1 test_func, F2 expect_func)186{187   typedef typename A::value_type         row_type;188   typedef Real                          value_type;189 190   test_result<value_type> result;191 192   for(unsigned i = 0; i < a.size(); ++i)193   {194      const row_type& row = a[i];195      value_type point;196#ifndef BOOST_NO_EXCEPTIONS197      try198      {199#endif200         point = test_func(row);201#ifndef BOOST_NO_EXCEPTIONS202      }203      catch(const std::underflow_error&)204      {205         point = 0;206      }207      catch(const std::overflow_error&)208      {209         point = std::numeric_limits<value_type>::has_infinity ?210            std::numeric_limits<value_type>::infinity()211            : tools::max_value<value_type>();212      }213      catch(const std::exception& e)214      {215         std::cerr << "Unexpected exception at entry: " << i << "\n";216         std::cerr << e.what() << std::endl;217         print_row(row, std::cerr);218         BOOST_ERROR("Unexpected exception.");219         // so we don't get further errors:220         point = expect_func(row);221      }222#endif223      value_type expected = expect_func(row);224      value_type err = relative_error(point, expected);225#ifdef BOOST_INSTRUMENT226      if(err != 0)227      {228         std::cout << row[0] << " " << err;229         if(std::numeric_limits<value_type>::is_specialized)230         {231            std::cout << " (" << err / std::numeric_limits<value_type>::epsilon() << "eps)";232         }233         std::cout << std::endl;234      }235#endif236      if(!(boost::math::isfinite)(point) && (boost::math::isfinite)(expected))237      {238         std::cerr << "CAUTION: Found non-finite result, when a finite value was expected at entry " << i << "\n";239         std::cerr << "Found: " << point << " Expected " << expected << " Error: " << err << std::endl;240         print_row(row, std::cerr);241         BOOST_ERROR("Unexpected non-finite result");242      }243      if(err > 0.5f)244      {245         std::cerr << "CAUTION: Gross error found at entry " << i << ".\n";246         std::cerr << "Found: " << point << " Expected " << expected << " Error: " << err << std::endl;247         print_row(row, std::cerr);248         BOOST_ERROR("Gross error");249      }250      result.add(err);251      if((result.max)() == err)252         result.set_worst(i);253   }254   return result;255}256 257#ifndef BOOST_MATH_NO_EXCEPTIONS258template <class Val, class Exception>259void test_check_throw(Val, Exception)260{261   BOOST_CHECK(errno);262   errno = 0;263}264 265template <class Val>266void test_check_throw(Val val, std::domain_error const*)267{268   BOOST_CHECK(errno == EDOM);269   errno = 0;270   if(std::numeric_limits<Val>::has_quiet_NaN)271   {272      BOOST_CHECK((boost::math::isnan)(val));273   }274}275 276template <class Val>277void test_check_throw(Val v, std::overflow_error const*)278{279   BOOST_CHECK(errno == ERANGE);280   errno = 0;281   BOOST_CHECK((v >= boost::math::tools::max_value<Val>()) || (v <= -boost::math::tools::max_value<Val>()));282}283 284template <class Val>285void test_check_throw(Val v, boost::math::rounding_error const*)286{287   BOOST_CHECK(errno == ERANGE);288   errno = 0;289   if(std::numeric_limits<Val>::is_specialized && std::numeric_limits<Val>::is_integer)290   {291      BOOST_CHECK((v == (std::numeric_limits<Val>::max)()) || (v == (std::numeric_limits<Val>::min)()));292   }293   else294   {295      BOOST_CHECK((v == boost::math::tools::max_value<Val>()) || (v == -boost::math::tools::max_value<Val>()));296   }297}298#endif299 300} // namespace tools301} // namespace math302} // namespace boost303 304 305  //306  // exception-free testing support, ideally we'd only define this in our tests,307  // but to keep things simple we really need it somewhere that's always included:308  //309#if defined(BOOST_MATH_NO_EXCEPTIONS) && defined(BOOST_MATH_HAS_GPU_SUPPORT)310#  define BOOST_MATH_CHECK_THROW(x, y)311#elif defined(BOOST_MATH_NO_EXCEPTIONS) 312#  define BOOST_MATH_CHECK_THROW(x, ExceptionType) boost::math::tools::test_check_throw(x, static_cast<ExceptionType const*>(nullptr));313#else314#  define BOOST_MATH_CHECK_THROW(x, y) BOOST_CHECK_THROW(x, y)315#endif316 317#endif318 319 320