test_interval.cpp 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. // Copyright (c) 2012 Robert Ramey
  2. //
  3. // Distributed under the Boost Software License, Version 1.0. (See
  4. // accompanying file LICENSE_1_0.txt or copy at
  5. // http://www.boost.org/LICENSE_1_0.txt)
  6. #include <iostream>
  7. #include <limits>
  8. #include <functional>
  9. #include <array>
  10. #include <boost/core/demangle.hpp>
  11. #include <boost/safe_numerics/checked_result.hpp>
  12. #include <boost/safe_numerics/checked_result_operations.hpp>
  13. #include <boost/safe_numerics/interval.hpp>
  14. template<typename T>
  15. using fptr = T (*)(const T &, const T &);
  16. template<typename T>
  17. using fptr_interval = fptr<boost::safe_numerics::interval<T>>;
  18. template<typename T>
  19. struct op {
  20. const fptr<T> m_f;
  21. const fptr_interval<T> m_finterval;
  22. const char * m_symbol;
  23. const bool skip_zeros;
  24. };
  25. template<
  26. typename T,
  27. unsigned int N
  28. >
  29. bool test_type_operator(
  30. const T (&value)[N],
  31. const op<T> & opi
  32. ){
  33. using namespace boost::safe_numerics;
  34. // for each pair of values p1, p2 (100)
  35. for(const T & l1 : value)
  36. for(const T & u1 : value){
  37. if(l1 > u1) continue; // skip reverse range
  38. const interval<T> p1(l1, u1);
  39. for(const T & l2 : value)
  40. for(const T & u2 : value){
  41. if(l2 > u2) continue; // skip reverse range
  42. const interval<T> p2(l2, u2);
  43. // maybe skip intervals which include zero
  44. if(opi.skip_zeros){
  45. if(l2 == safe_numerics_error::range_error
  46. || l2 == safe_numerics_error::domain_error
  47. || u2 == safe_numerics_error::range_error
  48. || u2 == safe_numerics_error::domain_error
  49. || p2.includes(T(0))
  50. )
  51. continue;
  52. }
  53. // create a new interval from the operation
  54. const interval<T> result_interval = opi.m_finterval(p1, p2);
  55. std::cout
  56. << p1 << opi.m_symbol << p2 << " -> " << result_interval << std::endl;
  57. // if resulting interval is null
  58. if(result_interval.u < result_interval.l)
  59. continue;
  60. // for each pair test values
  61. for(const T r1 : value)
  62. for(const T r2 : value){
  63. // calculate result of operation
  64. const T result = opi.m_f(r1, r2);
  65. if(result != safe_numerics_error::range_error
  66. && result != safe_numerics_error::domain_error ){
  67. // note usage of tribool logic here !!!
  68. // includes returns indeterminate the conditional
  69. // returns false in both cases and this is what we want.
  70. // This is very subtle, don't skim over this.
  71. // if both r1 and r2 are within they're respective bounds
  72. if(p1.includes(r1) && p2.includes(r2)
  73. && ! result_interval.includes(result)){
  74. #if 0
  75. const boost::logic::tribool b1 = p1.includes(r1);
  76. const boost::logic::tribool b2 = p2.includes(r2);
  77. const boost::logic::tribool b3 = result_interval.includes(result);
  78. const interval<T> result_intervalx = opi.m_finterval(p1, p2);
  79. const T resultx = opi.m_f(r1, r2);
  80. #endif
  81. return false;
  82. }
  83. }
  84. }
  85. }
  86. }
  87. return true;
  88. }
  89. // values
  90. // note: need to explicitly specify number of elements to avoid msvc failure
  91. template<typename T>
  92. const boost::safe_numerics::checked_result<T> value[8] = {
  93. boost::safe_numerics::safe_numerics_error::negative_overflow_error,
  94. std::numeric_limits<T>::lowest(),
  95. T(-1),
  96. T(0),
  97. T(1),
  98. std::numeric_limits<T>::max(),
  99. boost::safe_numerics::safe_numerics_error::positive_overflow_error,
  100. boost::safe_numerics::safe_numerics_error::domain_error
  101. };
  102. // note: need to explicitly specify number of elements to avoid msvc failure
  103. template<typename T>
  104. const boost::safe_numerics::checked_result<T> unsigned_value[6] = {
  105. boost::safe_numerics::safe_numerics_error::negative_overflow_error,
  106. T(0),
  107. T(1),
  108. std::numeric_limits<T>::max(),
  109. boost::safe_numerics::safe_numerics_error::positive_overflow_error,
  110. boost::safe_numerics::safe_numerics_error::domain_error
  111. };
  112. // invoke for each type
  113. struct test_type {
  114. unsigned int m_error_count;
  115. test_type() :
  116. m_error_count(0)
  117. {}
  118. template<typename T>
  119. bool operator()(const T &){
  120. using namespace boost::safe_numerics;
  121. std::cout
  122. << "** testing "
  123. << boost::core::demangle(typeid(T).name())
  124. << std::endl;
  125. using R = checked_result<T>;
  126. // pointers to operands for types T
  127. static const std::array<op<R>, 5> op_table{{
  128. {operator+, operator+, "+", false},
  129. {operator-, operator-, "-", false},
  130. {operator*, operator*, "*", false},
  131. {operator<<, operator<<, "<<", false},
  132. {operator>>, operator>>, ">>", false},
  133. }};
  134. //for(unsigned int i = 0; i < sizeof(op_table)/sizeof(op) / sizeof(fptr<R>); ++i){
  135. for(const op<R> & o : op_table){
  136. if(std::is_signed<T>::value){
  137. if(! test_type_operator(value<T>, o)){
  138. ++m_error_count;
  139. return false;
  140. }
  141. }
  142. else{
  143. if(! test_type_operator(unsigned_value<T>, o)){
  144. ++m_error_count;
  145. return false;
  146. }
  147. }
  148. }
  149. return true;
  150. }
  151. };
  152. #include <boost/mp11/list.hpp>
  153. #include <boost/mp11/algorithm.hpp>
  154. int main(int, char *[]){
  155. using namespace boost::mp11;
  156. // list of signed types
  157. using signed_types = mp_list<std::int8_t, std::int16_t, std::int32_t, std::int64_t>;
  158. // list of unsigned types
  159. using unsigned_types = mp_list<std::uint8_t, std::uint16_t, std::uint32_t, std::uint64_t>;
  160. test_type t;
  161. mp_for_each<unsigned_types>(t);
  162. mp_for_each<signed_types>(t);
  163. std::cout << (t.m_error_count == 0 ? "success!" : "failure") << std::endl;
  164. return t.m_error_count ;
  165. }