
Boost : 
Subject: Re: [boost] [Safe Numerics] floating point conversions
From: John Maddock (jz.maddock_at_[hidden])
Date: 20170312 11:49:54
>>
>> 3) If I assign a float to an integer, then I get the error: "conversion
>> of integer to float loses precision" which isn't quite what you meant to
>> say.
>> More particularly, for float conversions I would expect:
>>
>> * Conversion from a float holding an integer value that's within the
>> range of the target type to always succeed.
>> * Conversion from a float holding a nonintegral value to conditionally
>> succeed (with trunction) depending on the policy in effect.
>> * Conversion *to* a float may also fail if the integer is outside the
>> range of the float (no checking may be required if the number of bits in
>> the integer is less than the number of bits in the float).
>
> my implementation of this is sort of an afterthought and needs
> attention. It's similar to the case as above. It's not clear what I
> want to do  even to me.
>
> int i = 1.0
>
> I wonder what we're really doing here. In C++/C i get it. But when I
> write in C++ the value 1.0 I'm mean a value which in some sense
> approximates 1.0. I think it's mistake.
>
> int j = 1.5
>
> This is pretty clear to me. The fundamental premise of the library
> would be stated.
>
> "All expressions which change the arithmetic value are considered errors"
>
> On the other hand, I might be OK with
>
> int k = floor(1.5);
>
> I'm still sorting out how I feel about going back and forth between
> floats and integers.
>
Nod.
It's fairly common to see in floating point code, something like:
int integer_part = my_float;
double fractional_part = my_float  integer_part;
which is of course pretty seriously unsafe :(
Casting to a safe<int> to ensure there is no overflow would simplify a
lot of error checking code.
Now we could insist that my_float is passed through
floor/ceil/trunc/round before the conversion, and that's OK by me even
though the function call is superfluous in this instance, but since we
don't know where a floating point value has been, we can't actually
allow that, without also allowing assignment from any old float (albeit
with runtime checking).
BTW for the record, Boost.Math uses itrunc/ltrunc/lltrunc for this
operation which throws when the float is too large for the target type.
Lots of ways to tackle this, I just wanted you to be aware that there
are genuine use cases where floatinteroperability is useful and needed.
I guess there are several possible solutions:
Policies: we have 3 levels of checks:
* Permissive, allow all conversions from float and truncate (as long as
the truncated value is in range).
* Strict, only allow conversion from inrange integral values. Values
with fractional parts throw.
* Never: static assert on any attempt to convert from float.
An alternative is to use external functions, lets say we have:
template <class I, class F>
safe<I> safe_trunc(F f);
Which throws only when the truncated value is out of range. Likewise we
would need safe_round, safe_floor and safe_ceil. Obviously a certain
amount of "bike shed colouring" may be required on those names ;)
John.
 This email has been checked for viruses by AVG. http://www.avg.com
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk