test.hpp

来自「Boost provides free peer-reviewed portab」· HPP 代码 · 共 258 行

HPP
258
字号
//  (C) Copyright John Maddock 2006.//  Use, modification and distribution are subject to the//  Boost Software License, Version 1.0. (See accompanying file//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)#ifndef BOOST_MATH_TOOLS_TEST_HPP#define BOOST_MATH_TOOLS_TEST_HPP#ifdef _MSC_VER#pragma once#endif#include <boost/math/tools/config.hpp>#include <boost/math/tools/stats.hpp>#include <boost/math/special_functions/fpclassify.hpp>#include <boost/test/test_tools.hpp>#include <stdexcept>namespace boost{ namespace math{ namespace tools{template <class T>struct test_result{private:   boost::math::tools::stats<T> stat;   // Statistics for the test.   unsigned worst_case;                 // Index of the worst case test.public:   test_result() { worst_case = 0; }   void set_worst(int i){ worst_case = i; }   void add(const T& point){ stat.add(point); }   // accessors:   unsigned worst()const{ return worst_case; }   T min BOOST_PREVENT_MACRO_SUBSTITUTION()const{ return (stat.min)(); }   T max BOOST_PREVENT_MACRO_SUBSTITUTION()const{ return (stat.max)(); }   T total()const{ return stat.total(); }   T mean()const{ return stat.mean(); }   boost::uintmax_t count()const{ return stat.count(); }   T variance()const{ return stat.variance(); }   T variance1()const{ return stat.variance1(); }   T rms()const{ return stat.rms(); }   test_result& operator+=(const test_result& t)   {      if((t.stat.max)() > (stat.max)())         worst_case = t.worst_case;      stat += t.stat;      return *this;   }};template <class T>struct calculate_result_type{   typedef typename T::value_type row_type;   typedef typename row_type::value_type value_type;};template <class T>T relative_error(T a, T b){   BOOST_MATH_STD_USING#ifdef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS   //   // If math.h has no long double support we can't rely   // on the math functions generating exponents outside   // the range of a double:   //   T min_val = (std::max)(      tools::min_value<T>(),      static_cast<T>((std::numeric_limits<double>::min)()));   T max_val = (std::min)(      tools::max_value<T>(),      static_cast<T>((std::numeric_limits<double>::max)()));#else   T min_val = tools::min_value<T>();   T max_val = tools::max_value<T>();#endif   if((a != 0) && (b != 0))   {      // TODO: use isfinite:      if(fabs(b) >= max_val)      {         if(fabs(a) >= max_val)            return 0;  // one infinity is as good as another!      }      // If the result is denormalised, treat all denorms as equivalent:      if((a < min_val) && (a > 0))         a = min_val;      else if((a > -min_val) && (a < 0))         a = -min_val;      if((b < min_val) && (b > 0))         b = min_val;      else if((b > -min_val) && (b < 0))         b = -min_val;      return (std::max)(fabs((a-b)/a), fabs((a-b)/b));   }   // Handle special case where one or both are zero:   if(min_val == 0)      return fabs(a-b);   if(fabs(a) < min_val)      a = min_val;   if(fabs(b) < min_val)      b = min_val;   return (std::max)(fabs((a-b)/a), fabs((a-b)/b));}#if defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)template <>inline double relative_error<double>(double a, double b){   BOOST_MATH_STD_USING   //   // On Mac OS X we evaluate "double" functions at "long double" precision,   // but "long double" actually has a very slightly narrower range than "double"!     // Therefore use the range of "long double" as our limits since results outside   // that range may have been truncated to 0 or INF:   //   double min_val = (std::max)((double)tools::min_value<long double>(), tools::min_value<double>());   double max_val = (std::min)((double)tools::max_value<long double>(), tools::max_value<double>());   if((a != 0) && (b != 0))   {      // TODO: use isfinite:      if(b > max_val)      {         if(a > max_val)            return 0;  // one infinity is as good as another!      }      // If the result is denormalised, treat all denorms as equivalent:      if((a < min_val) && (a > 0))         a = min_val;      else if((a > -min_val) && (a < 0))         a = -min_val;      if((b < min_val) && (b > 0))         b = min_val;      else if((b > -min_val) && (b < 0))         b = -min_val;      return (std::max)(fabs((a-b)/a), fabs((a-b)/b));   }   // Handle special case where one or both are zero:   if(min_val == 0)      return fabs(a-b);   if(fabs(a) < min_val)      a = min_val;   if(fabs(b) < min_val)      b = min_val;   return (std::max)(fabs((a-b)/a), fabs((a-b)/b));}#endiftemplate <class T>void set_output_precision(T){   if(std::numeric_limits<T>::digits10)   {      std::cout << std::setprecision(std::numeric_limits<T>::digits10 + 2);   }}template <class Seq>void print_row(const Seq& row){   set_output_precision(row[0]);   for(unsigned i = 0; i < row.size(); ++i)   {      if(i)         std::cout << ", ";      std::cout << row[i];   }   std::cout << std::endl;}//// Function test accepts an matrix of input values (probably a 2D boost::array)// and calls two functors for each row in the array - one calculates a value// to test, and one extracts the expected value from the array (or possibly// calculates it at high precision).  The two functors are usually simple lambda// expressions.//template <class A, class F1, class F2>test_result<typename calculate_result_type<A>::value_type> test(const A& a, F1 test_func, F2 expect_func){   typedef typename A::value_type         row_type;   typedef typename row_type::value_type  value_type;   test_result<value_type> result;   for(unsigned i = 0; i < a.size(); ++i)   {      const row_type& row = a[i];      value_type point;      try      {         point = test_func(row);      }      catch(const std::underflow_error&)      {         point = 0;      }      catch(const std::overflow_error&)      {         point = std::numeric_limits<value_type>::has_infinity ?             std::numeric_limits<value_type>::infinity()            : tools::max_value<value_type>();      }      catch(const std::exception& e)      {         std::cerr << e.what() << std::endl;         print_row(row);         BOOST_ERROR("Unexpected exception.");         // so we don't get further errors:         point = expect_func(row);      }      value_type expected = expect_func(row);      value_type err = relative_error(point, expected);#ifdef BOOST_INSTRUMENT      if(err != 0)      {         std::cout << row[0] << " " << err;         if(std::numeric_limits<value_type>::is_specialized)         {            std::cout << " (" << err / std::numeric_limits<value_type>::epsilon() << "eps)";         }         std::cout << std::endl;      }#endif      if(!(boost::math::isfinite)(point) && (boost::math::isfinite)(expected))      {         std::cout << "CAUTION: Found non-finite result, when a finite value was expected at entry " << i << "\n";         std::cout << "Found: " << point << " Expected " << expected << " Error: " << err << std::endl;         print_row(row);         BOOST_ERROR("Unexpected non-finite result");      }      if(err > 0.5)      {         std::cout << "CAUTION: Gross error found at entry " << i << ".\n";         std::cout << "Found: " << point << " Expected " << expected << " Error: " << err << std::endl;         print_row(row);         BOOST_ERROR("Gross error");      }      result.add(err);      if((result.max)() == err)         result.set_worst(i);   }   return result;}} // namespace tools} // namespace math} // namespace boost#endif

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?