#include <ratio>
#include <type_traits>
#include <limits>
#include <stdexcept>
template< typename FLOAT, std::intmax_t NUM, std::intmax_t DENOM = 1 >
struct fp_as_ratio : std::ratio<NUM,DENOM>
{
static_assert( DENOM != 0, "infinity/NaN!" ) ;
using std::ratio<NUM,DENOM>::num ;
using std::ratio<NUM,DENOM>::den ;
static constexpr FLOAT value = num / FLOAT(den) ;
};
template< typename FLOAT, std::intmax_t LOWER_NUM, std::intmax_t LOWER_DEN,
std::intmax_t UPPER_NUM, std::intmax_t UPPER_DEN >
struct range_checked_fp
{
static_assert( std::is_floating_point<FLOAT>::value, "not a floating point type!" ) ;
using limits = std::numeric_limits<FLOAT> ;
using fp_low_value = fp_as_ratio<FLOAT,LOWER_NUM,LOWER_DEN> ;
using fp_high_value = fp_as_ratio<FLOAT,UPPER_NUM,UPPER_DEN> ;
static constexpr FLOAT low_value = fp_low_value::value ;
static constexpr FLOAT high_value = fp_high_value::value ;
static constexpr FLOAT epsilon = limits::epsilon() ; // modify as required
constexpr range_checked_fp() = default ;
range_checked_fp( FLOAT f ) : value(f)
{ if( !in_range(f) ) throw std::out_of_range( "floating point value is out of range!" ) ; }
constexpr operator FLOAT() const { return value ; }
private:
FLOAT value = fp_low_value::value ;
// adjust for epsilon?
static constexpr bool in_range( FLOAT v ) { return v >= low_value && v < high_value ; }
} ;
using percentage = range_checked_fp< float, 0, 1, 100, 1 > ; // 0 = 100
using probability = range_checked_fp< double, 0, 1, 1, 1 > ; // 0 - 1
#include <iostream>
int main()
{
percentage p = 52.3 ;
std::cout << p << '\n' ;
}
I2luY2x1ZGUgPHJhdGlvPgojaW5jbHVkZSA8dHlwZV90cmFpdHM+CiNpbmNsdWRlIDxsaW1pdHM+CiNpbmNsdWRlIDxzdGRleGNlcHQ+Cgp0ZW1wbGF0ZTwgdHlwZW5hbWUgRkxPQVQsIHN0ZDo6aW50bWF4X3QgTlVNLCBzdGQ6OmludG1heF90IERFTk9NID0gMSA+CnN0cnVjdCBmcF9hc19yYXRpbyA6IHN0ZDo6cmF0aW88TlVNLERFTk9NPgp7CiAgICBzdGF0aWNfYXNzZXJ0KCBERU5PTSAhPSAwLCAiaW5maW5pdHkvTmFOISIgKSA7CiAgICB1c2luZyBzdGQ6OnJhdGlvPE5VTSxERU5PTT46Om51bSA7CiAgICB1c2luZyBzdGQ6OnJhdGlvPE5VTSxERU5PTT46OmRlbiA7CiAgICBzdGF0aWMgY29uc3RleHByIEZMT0FUIHZhbHVlID0gbnVtIC8gRkxPQVQoZGVuKSA7Cn07Cgp0ZW1wbGF0ZTwgdHlwZW5hbWUgRkxPQVQsIHN0ZDo6aW50bWF4X3QgTE9XRVJfTlVNLCBzdGQ6OmludG1heF90IExPV0VSX0RFTiwKICAgICAgICAgICAgICAgICAgICAgICAgICBzdGQ6OmludG1heF90IFVQUEVSX05VTSwgc3RkOjppbnRtYXhfdCBVUFBFUl9ERU4gPgpzdHJ1Y3QgcmFuZ2VfY2hlY2tlZF9mcAp7CiAgICBzdGF0aWNfYXNzZXJ0KCBzdGQ6OmlzX2Zsb2F0aW5nX3BvaW50PEZMT0FUPjo6dmFsdWUsICJub3QgYSBmbG9hdGluZyBwb2ludCB0eXBlISIgKSA7CgogICAgdXNpbmcgbGltaXRzID0gc3RkOjpudW1lcmljX2xpbWl0czxGTE9BVD4gOwogICAgdXNpbmcgZnBfbG93X3ZhbHVlID0gZnBfYXNfcmF0aW88RkxPQVQsTE9XRVJfTlVNLExPV0VSX0RFTj4gOwogICAgdXNpbmcgZnBfaGlnaF92YWx1ZSA9IGZwX2FzX3JhdGlvPEZMT0FULFVQUEVSX05VTSxVUFBFUl9ERU4+IDsKCiAgICBzdGF0aWMgY29uc3RleHByIEZMT0FUIGxvd192YWx1ZSA9IGZwX2xvd192YWx1ZTo6dmFsdWUgOwogICAgc3RhdGljIGNvbnN0ZXhwciBGTE9BVCBoaWdoX3ZhbHVlID0gZnBfaGlnaF92YWx1ZTo6dmFsdWUgOwogICAgc3RhdGljIGNvbnN0ZXhwciBGTE9BVCBlcHNpbG9uID0gbGltaXRzOjplcHNpbG9uKCkgOyAvLyBtb2RpZnkgYXMgcmVxdWlyZWQKCiAgICBjb25zdGV4cHIgcmFuZ2VfY2hlY2tlZF9mcCgpID0gZGVmYXVsdCA7CiAgICByYW5nZV9jaGVja2VkX2ZwKCBGTE9BVCBmICkgOiB2YWx1ZShmKQogICAgeyBpZiggIWluX3JhbmdlKGYpICkgdGhyb3cgc3RkOjpvdXRfb2ZfcmFuZ2UoICJmbG9hdGluZyBwb2ludCB2YWx1ZSBpcyBvdXQgb2YgcmFuZ2UhIiApIDsgfQoKICAgIGNvbnN0ZXhwciBvcGVyYXRvciBGTE9BVCgpIGNvbnN0IHsgcmV0dXJuIHZhbHVlIDsgfQoKICAgIHByaXZhdGU6CiAgICAgICAgRkxPQVQgdmFsdWUgPSBmcF9sb3dfdmFsdWU6OnZhbHVlICA7CgogICAgICAgIC8vIGFkanVzdCBmb3IgZXBzaWxvbj8KICAgICAgICBzdGF0aWMgY29uc3RleHByIGJvb2wgaW5fcmFuZ2UoIEZMT0FUIHYgKSB7IHJldHVybiB2ID49IGxvd192YWx1ZSAmJiB2IDwgaGlnaF92YWx1ZSA7IH0KfSA7Cgp1c2luZyBwZXJjZW50YWdlID0gcmFuZ2VfY2hlY2tlZF9mcDwgZmxvYXQsIDAsIDEsIDEwMCwgMSA+IDsgLy8gMCA9IDEwMAp1c2luZyBwcm9iYWJpbGl0eSA9IHJhbmdlX2NoZWNrZWRfZnA8IGRvdWJsZSwgMCwgMSwgMSwgMSA+IDsgLy8gMCAtIDEKCiNpbmNsdWRlIDxpb3N0cmVhbT4KCmludCBtYWluKCkKewogICAgcGVyY2VudGFnZSBwID0gNTIuMyA7CiAgICBzdGQ6OmNvdXQgPDwgcCA8PCAnXG4nIDsKfQo=