|
Boost : |
Subject: Re: [boost] Safe Float design question
From: Andrzej Krzemienski (akrzemi1_at_[hidden])
Date: 2018-07-17 11:12:53
One more thing. Is there a need to keep every single aspect separate? E.g.,
is there a point in requiring that overflow is checked, but underflow is
ignored?
I see the point in in treating inaccurate representation as a separate
thing (because you will not want to have it most of the time), but things
like overflow and underflow -- do you not want them to always go in pair?
Also, given that safe_float<double> is to be a "drop-in" replacement for
double, type double is convertible to types int, unsigned int and bool.
Is safe_float<double> also going to be convertible to these types? If the
answer should be yes, do these conversions also require a dedicated policy?
Regards,
&rzej;
2018-07-17 10:55 GMT+02:00 Andrzej Krzemienski <akrzemi1_at_[hidden]>:
> Hi Damian,
> I may not be answering your question directly, but maybe the following
> will help.
>
> You mention checking things as:
> - I would like to check there was no "overflow_to_infinite" in "addition
> operations", otherwise I "throw exception"..
> - I would like to check there was no "division by zero" in "division",
> otherwise I will "log to cerr and ignore it".
>
> The two checks are very different in nature, and I do not even think they
> belong into the same library. The first check traps a situation that (1)
> the programmer-user cannot control (you do not know in advance if the
> operation would overflow, it is not a bug to cause overflow), (2) Type
> double has an inconvenient way of handling the situation (does not report
> an error), so you want your type to handle it better.
>
> The later check checks for programmer mistakes. These mistakes should not
> be handled at run-time, but corrected in the code (the overflow cannot be
> easily corrected in the code), and it adds overhead for situations that do
> not occur for correct programs. The precondition violation should be
> handled by contract libraries: otherwise you are preventing static-analysis
> tools and UB sanitizers from finding division-by-zero bugs.
>
> Next, if you go with providing checks separately from the method of
> reporting them:
>
> using sf = safe_float<float, CHECK, REPORT>;
>
> You will loose the ability to report different kinds of errors in
> different ways. You have to make the call: do you always want all checks to
> be reported in the same way, or do you want, for instance to allow
> reporting the inaccurate addition in a different way than overflowing to
> infinity? If the latter, you will have to encode the method of handling
> inside the check:
>
> using P = compose_policy<
> check_addition_overflow< report_throw_on_failure >,
> check_division_underflow< abort_on_failure >
> >;
>
> The design, where I first need to write 10 lines to build a policy, and
> then define a type:
>
> using fp = safe_float<double, P>;
>
> seems the right choice to me. Of course, you should provide some
> predefined policies, that would be most obviously chosen most of the time.
> (Like, check and throw only underflow and overflow, check and abort only on
> underflow and overflow).
>
> Regards,
> &rzej;
>
> Finally
> 2018-07-17 4:18 GMT+02:00 Damian Vicino via Boost <boost_at_[hidden]>:
>
>> Hi,
>> I looking for some design advice.
>>
>> The context:
>> - I'm revisiting SafeFloat after some time and, while doing so, I'm
>> rethinking all the decisions from the past. Idea is to sent for review in
>> the following months.
>> - The goal of the library is being a drop-in replacement for float, that
>> adds checks to floating point operations and reports when a check failed.
>>
>> Without SafeFloat, someone could write something like this:
>>
>> #include <iostream>
>> #include <limits>
>> #include <cfenv>
>>
>> using namespace std;
>>
>> int main(){
>> float a = 1.0f;
>> float b = numeric_limits<float>::max();
>> feclearexcept(FE_ALL_EXCEPT);
>> float c = a/b;
>> if(fetestexcept(FE_UNDERFLOW)) { cout << "underflow result\n"; }
>> }
>>
>>
>> What I expect when using safe_float is to declare upfront "what checks" I
>> care about, "what operations" to check, and "what to do when a check
>> fails".
>>
>> Some intention examples:
>> - I would like to check there was no "overflow_to_infinite" in "addition
>> operations", otherwise I "throw exception"..
>> - I would like to check there was no "division by zero" in "division",
>> otherwise I will "log to cerr and ignore it".
>> - I would like to check there was no "inexact" "addition", otherwise I
>> return an boost::unexpected.
>>
>> I have at least 5 things to check (there is 5 flags in c++11::fenv). I
>> have
>> at least 4 places to check (+/-/*//) and I want to keep what to do about
>> it
>> customizable.
>>
>> In addition, sometimes I want to check multiple things "overflow and
>> underflow", etc...
>>
>> So, the question is how the user can pass all that information to the type
>> and it doesn't look as horrible nonsense.
>>
>> My original option was:
>> int main(){
>> using CHECK = compose_policy<check_addition_overflow,
>> check_division_by_zero, check_division_underflow>::type;
>> using REPORT = report_throw_on_failure;
>> using sf = safe_float<float, CHECK, REPORT>;
>>
>> try{
>> sf a = 1.0_sf;
>> sf b = numeric_limits<sf>::max();
>> auto c = a/b;
>> } catch (safe_float_exception e){
>> cout << e.message(); //this outputs there was a underflow
>> }
>>
>> }
>>
>>
>> Please comment in what you think about this way to use. Is there a better
>> way to specify the policies to apply that I should try?
>>
>> Best regards,
>> Damian
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>> I expect when using safe float to write some code like this:
>>
>> int main(){
>>
>> safe_float<float>
>>
>>
>> }
>>
>> _______________________________________________
>> Unsubscribe & other changes: http://lists.boost.org/mailman
>> /listinfo.cgi/boost
>>
>
>
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk