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