test_value.hpp 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. // Copyright Paul A. Bristow 2017.
  2. // Copyright John Maddock 2017.
  3. // Use, modification and distribution are subject to the
  4. // Boost Software License, Version 1.0.
  5. // (See accompanying file LICENSE_1_0.txt
  6. // or copy at http://www.boost.org/LICENSE_1_0.txt)
  7. // test_value.hpp
  8. #ifndef TEST_VALUE_HPP
  9. #define TEST_VALUE_HPP
  10. // BOOST_MATH_TEST_VALUE is used to create a test value of suitable type from a decimal digit string.
  11. // Two parameters, both a floating-point literal double like 1.23 (not long double so no suffix L)
  12. // and a decimal digit string const char* like "1.23" must be provided.
  13. // The decimal value represented must be the same of course, with at least enough precision for long double.
  14. // Note there are two gotchas to this approach:
  15. // * You need all values to be real floating-point values
  16. // * and *MUST* include a decimal point (to avoid confusion with an integer literal).
  17. // * It's slow to compile compared to a simple literal.
  18. // Speed is not an issue for a few test values,
  19. // but it's not generally usable in large tables
  20. // where you really need everything to be statically initialized.
  21. // Macro BOOST_MATH_INSTRUMENT_CREATE_TEST_VALUE provides a global diagnostic value for create_type.
  22. #include <boost/cstdfloat.hpp> // For float_64_t, float128_t. Must be first include!
  23. #ifndef BOOST_MATH_STANDALONE
  24. #include <boost/lexical_cast.hpp>
  25. #endif
  26. #include <limits>
  27. #include <type_traits>
  28. #ifdef BOOST_MATH_INSTRUMENT_CREATE_TEST_VALUE
  29. // global int create_type(0); must be defined before including this file.
  30. #endif
  31. #ifdef BOOST_HAS_FLOAT128
  32. typedef __float128 largest_float;
  33. #define BOOST_MATH_TEST_LARGEST_FLOAT_SUFFIX(x) x##Q
  34. #define BOOST_MATH_TEST_LARGEST_FLOAT_DIGITS 113
  35. #else
  36. typedef long double largest_float;
  37. #define BOOST_MATH_TEST_LARGEST_FLOAT_SUFFIX(x) x##L
  38. #define BOOST_MATH_TEST_LARGEST_FLOAT_DIGITS std::numeric_limits<long double>::digits
  39. #endif
  40. template <class T, class T2>
  41. inline T create_test_value(largest_float val, const char*, const std::true_type&, const T2&)
  42. { // Construct from long double or quad parameter val (ignoring string/const char* str).
  43. // (This is case for MPL parameters = true_ and T2 == false_,
  44. // and MPL parameters = true_ and T2 == true_ cpp_bin_float)
  45. // All built-in/fundamental floating-point types,
  46. // and other User-Defined Types that can be constructed without loss of precision
  47. // from long double suffix L (or quad suffix Q),
  48. //
  49. // Choose this method, even if can be constructed from a string,
  50. // because it will be faster, and more likely to be the closest representation.
  51. // (This is case for MPL parameters = true_type and T2 == true_type).
  52. #ifdef BOOST_MATH_INSTRUMENT_CREATE_TEST_VALUE
  53. create_type = 1;
  54. #endif
  55. return static_cast<T>(val);
  56. }
  57. template <class T>
  58. inline T create_test_value(largest_float, const char* str, const std::false_type&, const std::true_type&)
  59. { // Construct from decimal digit string const char* @c str (ignoring long double parameter).
  60. // For example, extended precision or other User-Defined types which ARE constructible from a string
  61. // (but not from double, or long double without loss of precision).
  62. // (This is case for MPL parameters = false_type and T2 == true_type).
  63. #ifdef BOOST_MATH_INSTRUMENT_CREATE_TEST_VALUE
  64. create_type = 2;
  65. #endif
  66. return T(str);
  67. }
  68. template <class T>
  69. inline T create_test_value(largest_float, const char* str, const std::false_type&, const std::false_type&)
  70. { // Create test value using from lexical cast of decimal digit string const char* str.
  71. // For example, extended precision or other User-Defined types which are NOT constructible from a string
  72. // (NOR constructible from a long double).
  73. // (This is case T1 = false_type and T2 == false_type).
  74. #ifdef BOOST_MATH_INSTRUMENT_CREATE_TEST_VALUE
  75. create_type = 3;
  76. #endif
  77. #if defined(BOOST_MATH_STANDALONE)
  78. static_assert(sizeof(T) == 0, "Can not create a test value using lexical cast of string in standalone mode");
  79. return T();
  80. #else
  81. return boost::lexical_cast<T>(str);
  82. #endif
  83. }
  84. // T real type, x a decimal digits representation of a floating-point, for example: 12.34.
  85. // It must include a decimal point (or it would be interpreted as an integer).
  86. // x is converted to a long double by appending the letter L (to suit long double fundamental type), 12.34L.
  87. // x is also passed as a const char* or string representation "12.34"
  88. // (to suit most other types that cannot be constructed from long double without possible loss).
  89. // BOOST_MATH_TEST_LARGEST_FLOAT_SUFFIX(x) makes a long double or quad version, with
  90. // suffix a letter L (or Q) to suit long double (or quad) fundamental type, 12.34L or 12.34Q.
  91. // #x makes a decimal digit string version to suit multiprecision and fixed_point constructors, "12.34".
  92. // (Constructing from double or long double (or quad) could lose precision for multiprecision or fixed-point).
  93. // The matching create_test_value function above is chosen depending on the T1 and T2 mpl bool truths.
  94. // The string version from #x is used if the precision of T is greater than long double.
  95. // Example: long double test_value = BOOST_MATH_TEST_VALUE(double, 1.23456789);
  96. #define BOOST_MATH_TEST_VALUE(T, x) create_test_value<T>(\
  97. BOOST_MATH_TEST_LARGEST_FLOAT_SUFFIX(x),\
  98. #x,\
  99. std::integral_constant<bool, \
  100. std::numeric_limits<T>::is_specialized &&\
  101. (std::numeric_limits<T>::radix == 2)\
  102. && (std::numeric_limits<T>::digits <= BOOST_MATH_TEST_LARGEST_FLOAT_DIGITS)\
  103. && std::is_convertible<largest_float, T>::value>(),\
  104. std::integral_constant<bool, \
  105. std::is_constructible<T, const char*>::value>()\
  106. )
  107. #if LDBL_MAX_10_EXP > DBL_MAX_10_EXP
  108. #define BOOST_MATH_TEST_HUGE_FLOAT_SUFFIX(x) BOOST_MATH_TEST_LARGEST_FLOAT_SUFFIX(x)
  109. #else
  110. #define BOOST_MATH_TEST_HUGE_FLOAT_SUFFIX(x) 0.0
  111. #endif
  112. #define BOOST_MATH_HUGE_TEST_VALUE(T, x) create_test_value<T>(\
  113. BOOST_MATH_TEST_HUGE_FLOAT_SUFFIX(x),\
  114. #x,\
  115. std::integral_constant<bool, \
  116. std::numeric_limits<T>::is_specialized &&\
  117. (std::numeric_limits<T>::radix == 2)\
  118. && (std::numeric_limits<T>::digits <= BOOST_MATH_TEST_LARGEST_FLOAT_DIGITS)\
  119. && std::is_convertible<largest_float, T>::value>(),\
  120. std::integral_constant<bool, \
  121. std::is_constructible<T, const char*>::value>()\
  122. )
  123. #endif // TEST_VALUE_HPP