constrained_value question

I have used constrained_value to prototype a fixed-pt class. It seems to be developing nicely. One thing might be useful is to have the option to record minimum and maximum values that are used during a given computation. Right now, I have: template<int int_bits, int frac_bits, typename base_type=int, typename error_policy=cv::throw_exception<>, typename round_policy=rnd<frac_bits,base_type> > struct fixed_pt : ... { typedef fixed_pt<int_bits,frac_bits,base_type,error_policy,round_policy> self; static const int total_bits = int_bits + frac_bits; static const base_type max = ~(base_type(-1) << (total_bits-1)); static const base_type min = (base_type(-1) << (total_bits-1)); typedef typename cv::bounded_int<base_type, min, max,true,true,error_policy>::type val_t; ... val_t value; } So fixed_pt<> contains a bounded_int member. I'm wondering how to add a facility to track extremal values. It would seem to be nice to add it into the 'value' member itself, but I suspect this concept doesn't really fit with the constrained_value design.

From: Neal Becker One thing might be useful is to have the option to record minimum and maximum values that are used during a given computation.
You can write error policy: struct stretchy_policy { template <typename V, typename C> void operator () (const V &, const V & new_val, C & constraint) { if( constraint.is_below(new_val) ) constraint.lower_bound() = new_val; else constraint.upper_bound() = new_val; } }; And then use it like this: // int wrapper that remembers extreme values assigned to it: typedef bounded< int, int, int, value_generator<bool, true>, // bounds have to be included if we value_generator<bool, true>, // want them to indicate valid values stretchy_policy
::type cool_int;
cool_int i(4, cool_int::constraint_type(4, 4)); // note: should initialise bounds too i = -1; i = 10; assert( i.constraint().lower_bound() == -1 && i.constraint().upper_bound() == 10 ); Of course this will not allow you to do bounds-checking, but you can nest cool_int in another bounded type: typedef bounded< cool_int, value_generator<int, 0>, value_generator<int, 100>, value_generator<bool, true>, value_generator<bool, true>, throw_exception<>, std::less<int> // needed to avoid problems with conversions
::type splendid_int;
Now you have int that must be in the range [0, 100] and remembers its extreme values. I haven't compiled the code and can't tell it works for sure, but in general the idea seems to be valid. ;-) Best regards, Robert

Robert Kawulak wrote:
From: Neal Becker One thing might be useful is to have the option to record minimum and maximum values that are used during a given computation.
You can write error policy:
struct stretchy_policy { template <typename V, typename C> void operator () (const V &, const V & new_val, C & constraint) { if( constraint.is_below(new_val) ) constraint.lower_bound() = new_val; else constraint.upper_bound() = new_val; } };
And then use it like this:
// int wrapper that remembers extreme values assigned to it: typedef bounded< int, int, int, value_generator<bool, true>, // bounds have to be included if we value_generator<bool, true>, // want them to indicate valid values stretchy_policy
::type cool_int;
cool_int i(4, cool_int::constraint_type(4, 4)); // note: should initialise bounds too i = -1; i = 10; assert( i.constraint().lower_bound() == -1 && i.constraint().upper_bound() == 10 );
Of course this will not allow you to do bounds-checking, but you can nest cool_int in another bounded type:
typedef bounded< cool_int, value_generator<int, 0>, value_generator<int, 100>, value_generator<bool, true>, value_generator<bool, true>, throw_exception<>, std::less<int> // needed to avoid problems with conversions
::type splendid_int;
Now you have int that must be in the range [0, 100] and remembers its extreme values.
I haven't compiled the code and can't tell it works for sure, but in general the idea seems to be valid. ;-)
It wouldn't be part of the error_policy, since the extrema might be within bounds and error_handler wouldn't then be invoked. I was thinking maybe to extend within_bounds, either by inheritance or aggregation?

From: Neal Becker Robert Kawulak wrote:
You can write error policy:
struct stretchy_policy { template <typename V, typename C> void operator () (const V &, const V & new_val, C & constraint) { if( constraint.is_below(new_val) ) constraint.lower_bound() = new_val; else constraint.upper_bound() = new_val; } }; [snip] It wouldn't be part of the error_policy, since the extrema might be within bounds and error_handler wouldn't then be invoked.
I'm not sure I get what's your point here. The idea is to make an error policy, which, when "error" is detected (out-of-bounds value assigned), corrects the bounds to make the new value fit within them. This way the bounds actually are the extrema. Of course, if the error handler is not invoked, this means that the value is between the past extrema and therefore no extremum is updated. Best regards, Robert

Robert Kawulak wrote:
From: Neal Becker Robert Kawulak wrote:
You can write error policy:
struct stretchy_policy { template <typename V, typename C> void operator () (const V &, const V & new_val, C & constraint) { if( constraint.is_below(new_val) ) constraint.lower_bound() = new_val; else constraint.upper_bound() = new_val; } }; [snip] It wouldn't be part of the error_policy, since the extrema might be within bounds and error_handler wouldn't then be invoked.
I'm not sure I get what's your point here. The idea is to make an error policy, which, when "error" is detected (out-of-bounds value assigned), corrects the bounds to make the new value fit within them. This way the bounds actually are the extrema. Of course, if the error handler is not invoked, this means that the value is between the past extrema and therefore no extremum is updated.
OK, I see the confusion. My idea was to record extrema _in addition to_ some other error policy. For example, throw if out of bounds, but also collect extrema data. In this case the error policy would not normally happen.

Neal Becker wrote:
Robert Kawulak wrote:
From: Neal Becker One thing might be useful is to have the option to record minimum and maximum values that are used during a given computation.
... It would be easy to do this by making my own compare_type (with memory), except for the unfortunate fact that within_bounds doesn't (currently) always call with the arguments in the same order:
if( lower_bound_included() ) return compare()(value, lower_bound()); else return !compare()(lower_bound(), value);
participants (2)
-
Neal Becker
-
Robert Kawulak