fork download
  1. #include <ratio>
  2. #include <type_traits>
  3. #include <limits>
  4. #include <stdexcept>
  5.  
  6. template< typename FLOAT, std::intmax_t NUM, std::intmax_t DENOM = 1 >
  7. struct fp_as_ratio : std::ratio<NUM,DENOM>
  8. {
  9. static_assert( DENOM != 0, "infinity/NaN!" ) ;
  10. using std::ratio<NUM,DENOM>::num ;
  11. using std::ratio<NUM,DENOM>::den ;
  12. static constexpr FLOAT value = num / FLOAT(den) ;
  13. };
  14.  
  15. template< typename FLOAT, std::intmax_t LOWER_NUM, std::intmax_t LOWER_DEN,
  16. std::intmax_t UPPER_NUM, std::intmax_t UPPER_DEN >
  17. struct range_checked_fp
  18. {
  19. static_assert( std::is_floating_point<FLOAT>::value, "not a floating point type!" ) ;
  20.  
  21. using limits = std::numeric_limits<FLOAT> ;
  22. using fp_low_value = fp_as_ratio<FLOAT,LOWER_NUM,LOWER_DEN> ;
  23. using fp_high_value = fp_as_ratio<FLOAT,UPPER_NUM,UPPER_DEN> ;
  24.  
  25. static constexpr FLOAT low_value = fp_low_value::value ;
  26. static constexpr FLOAT high_value = fp_high_value::value ;
  27. static constexpr FLOAT epsilon = limits::epsilon() ; // modify as required
  28.  
  29. constexpr range_checked_fp() = default ;
  30. range_checked_fp( FLOAT f ) : value(f)
  31. { if( !in_range(f) ) throw std::out_of_range( "floating point value is out of range!" ) ; }
  32.  
  33. constexpr operator FLOAT() const { return value ; }
  34.  
  35. private:
  36. FLOAT value = fp_low_value::value ;
  37.  
  38. // adjust for epsilon?
  39. static constexpr bool in_range( FLOAT v ) { return v >= low_value && v < high_value ; }
  40. } ;
  41.  
  42. using percentage = range_checked_fp< float, 0, 1, 100, 1 > ; // 0 = 100
  43. using probability = range_checked_fp< double, 0, 1, 1, 1 > ; // 0 - 1
  44.  
  45. #include <iostream>
  46.  
  47. int main()
  48. {
  49. percentage p = 52.3 ;
  50. std::cout << p << '\n' ;
  51. }
  52.  
Success #stdin #stdout 0s 3340KB
stdin
Standard input is empty
stdout
52.3