| // (C) Copyright John Maddock 2006-7. |
| // 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_HANDLE_TEST_RESULT |
| #define BOOST_MATH_HANDLE_TEST_RESULT |
| |
| #include <boost/math/tools/stats.hpp> |
| #include <boost/math/tools/test.hpp> |
| #include <boost/math/tools/precision.hpp> |
| #include <boost/regex.hpp> |
| #include <boost/test/test_tools.hpp> |
| |
| #if defined(BOOST_INTEL) |
| # pragma warning(disable:239) |
| # pragma warning(disable:264) |
| #endif |
| |
| // |
| // Every client of this header has to define this function, |
| // and initialise the table of expected results: |
| // |
| void expected_results(); |
| |
| typedef std::pair<boost::regex, std::pair<boost::uintmax_t, boost::uintmax_t> > expected_data_type; |
| typedef std::list<expected_data_type> list_type; |
| |
| inline list_type& |
| get_expected_data() |
| { |
| static list_type data; |
| return data; |
| } |
| |
| inline void add_expected_result( |
| const char* compiler, |
| const char* library, |
| const char* platform, |
| const char* type_name, |
| const char* test_name, |
| const char* group_name, |
| boost::uintmax_t max_peek_error, |
| boost::uintmax_t max_mean_error) |
| { |
| std::string re("(?:"); |
| re += compiler; |
| re += ")"; |
| re += "\\|"; |
| re += "(?:"; |
| re += library; |
| re += ")"; |
| re += "\\|"; |
| re += "(?:"; |
| re += platform; |
| re += ")"; |
| re += "\\|"; |
| re += "(?:"; |
| re += type_name; |
| re += ")"; |
| re += "\\|"; |
| re += "(?:"; |
| re += test_name; |
| re += ")"; |
| re += "\\|"; |
| re += "(?:"; |
| re += group_name; |
| re += ")"; |
| get_expected_data().push_back( |
| std::make_pair(boost::regex(re, boost::regex::perl | boost::regex::icase), |
| std::make_pair(max_peek_error, max_mean_error))); |
| } |
| |
| inline std::string build_test_name(const char* type_name, const char* test_name, const char* group_name) |
| { |
| std::string result(BOOST_COMPILER); |
| result += "|"; |
| result += BOOST_STDLIB; |
| result += "|"; |
| result += BOOST_PLATFORM; |
| result += "|"; |
| result += type_name; |
| result += "|"; |
| result += group_name; |
| result += "|"; |
| result += test_name; |
| return result; |
| } |
| |
| inline const std::pair<boost::uintmax_t, boost::uintmax_t>& |
| get_max_errors(const char* type_name, const char* test_name, const char* group_name) |
| { |
| static const std::pair<boost::uintmax_t, boost::uintmax_t> defaults(1, 1); |
| std::string name = build_test_name(type_name, test_name, group_name); |
| list_type& l = get_expected_data(); |
| list_type::const_iterator a(l.begin()), b(l.end()); |
| while(a != b) |
| { |
| if(regex_match(name, a->first)) |
| { |
| #if 0 |
| std::cout << name << std::endl; |
| std::cout << a->first.str() << std::endl; |
| #endif |
| return a->second; |
| } |
| ++a; |
| } |
| return defaults; |
| } |
| |
| template <class T, class Seq> |
| void handle_test_result(const boost::math::tools::test_result<T>& result, |
| const Seq& worst, int row, |
| const char* type_name, |
| const char* test_name, |
| const char* group_name) |
| { |
| using namespace std; // To aid selection of the right pow. |
| T eps = boost::math::tools::epsilon<T>(); |
| std::cout << std::setprecision(4); |
| |
| T max_error_found = (result.max)()/eps; |
| T mean_error_found = result.rms()/eps; |
| // |
| // Begin by printing the main tag line with the results: |
| // |
| std::cout << test_name << "<" << type_name << "> Max = " << max_error_found |
| << " RMS Mean=" << mean_error_found; |
| // |
| // If the max error is non-zero, give the row of the table that |
| // produced the worst error: |
| // |
| if((result.max)() != 0) |
| { |
| std::cout << "\n worst case at row: " |
| << row << "\n { "; |
| if(std::numeric_limits<T>::digits10) |
| { |
| std::cout << std::setprecision(std::numeric_limits<T>::digits10 + 2); |
| } |
| else |
| { |
| std::cout << std::setprecision(std::numeric_limits<long double>::digits10 + 2); |
| } |
| for(unsigned i = 0; i < worst.size(); ++i) |
| { |
| if(i) |
| std::cout << ", "; |
| #if defined(__SGI_STL_PORT) |
| std::cout << boost::math::tools::real_cast<double>(worst[i]); |
| #else |
| std::cout << worst[i]; |
| #endif |
| } |
| std::cout << " }"; |
| } |
| std::cout << std::endl; |
| // |
| // Now verify that the results are within our expected bounds: |
| // |
| std::pair<boost::uintmax_t, boost::uintmax_t> const& bounds = get_max_errors(type_name, test_name, group_name); |
| if(bounds.first < max_error_found) |
| { |
| std::cerr << "Peak error greater than expected value of " << bounds.first << std::endl; |
| BOOST_CHECK(bounds.first >= max_error_found); |
| } |
| if(bounds.second < mean_error_found) |
| { |
| std::cerr << "Mean error greater than expected value of " << bounds.second << std::endl; |
| BOOST_CHECK(bounds.second >= mean_error_found); |
| } |
| std::cout << std::endl; |
| } |
| |
| template <class T, class Seq> |
| void print_test_result(const boost::math::tools::test_result<T>& result, |
| const Seq& worst, int row, const char* name, const char* test) |
| { |
| using namespace std; // To aid selection of the right pow. |
| T eps = boost::math::tools::epsilon<T>(); |
| std::cout << std::setprecision(4); |
| |
| T max_error_found = (result.max)()/eps; |
| T mean_error_found = result.rms()/eps; |
| // |
| // Begin by printing the main tag line with the results: |
| // |
| std::cout << test << "(" << name << ") Max = " << max_error_found |
| << " RMS Mean=" << mean_error_found; |
| // |
| // If the max error is non-zero, give the row of the table that |
| // produced the worst error: |
| // |
| if((result.max)() != 0) |
| { |
| std::cout << "\n worst case at row: " |
| << row << "\n { "; |
| for(unsigned i = 0; i < worst.size(); ++i) |
| { |
| if(i) |
| std::cout << ", "; |
| std::cout << worst[i]; |
| } |
| std::cout << " }"; |
| } |
| std::cout << std::endl; |
| } |
| |
| #endif // BOOST_MATH_HANDLE_TEST_RESULT |
| |