lmi
[Top][All Lists]

## Re: [lmi] Two kinds of precision loss

 From: Vadim Zeitlin Subject: Re: [lmi] Two kinds of precision loss Date: Wed, 22 Mar 2017 16:44:15 +0100

```On Tue, 21 Mar 2017 22:34:35 +0000 Greg Chicares <address@hidden> wrote:

GC> There are three problems in mapping between floating and integral types:
GC>
GC> (1) Loss of range, e.g., DBL_MAX --> int: UB; definitely not wanted.

Agreed.

GC> (2) Truncation, e.g., M_PI --> int: we agree that we don't want this.

And one of the reasons for this is that this conversion is possibly
ambiguous, e.g. converting 3.5 to int could be reasonably expected to give
either 3 or 4 and there is no universally correct answer.

GC> (3) Loss of precision, e.g., ULLONG_MAX --> float: here, static_cast
GC> gives a well-defined result [4.9/2] that is as good an approximation
GC> as it can be, plus or minus one ulp; a sufficiently wide hypothetical
GC> "long long double" type could be exact. Is this okay for bourn_cast?

It is if and only if we consider the reason above the only important one:
then, this case is fine because you really can't expect to get anything
else, i.e. there is no ambiguity. However if you also expect the cast to be
round-trip safe, then this one is still not OK.

Of course, this just replaces one question with another: do we need
round-trip safety from bourn_cast? Personally I think it's nice to have but
I can't find any reason to absolutely require it here.

GC> Let me share a curious example that arose when I tried to write a unit
GC> test for this exact case. I'm using
GC>   float = 32-bit IEEE 754
GC>   unsigned long long = 64-bit integer
GC>
GC> snprintf() results:
GC>
GC>   18446744073709551615 == 2^64 - 1 = ULLONG_MAX
GC>   18446744073709551616 == static_cast<float>(ULLONG_MAX)
GC>                      ^different only in the last digit shown
GC>
GC> Cast either to the type of the other, and they compare equal. I think
GC> I'll wait until April Fools' Day and report this here:
GC>   https://gcc.gnu.org/bugzilla/show_bug.cgi?id=323

This would be really cruel. But not as cruel as using this as an interview
question for C++ programmers -- I'm pretty sure that if I was asked whether
there exist 2 values which compare equal after a cast to either of their
types but are still different, I would answer "no" almost without thinking.

GC> But seriously...we agree that bourn_cast should throw in case (1)
GC> above, and should throw also in case (2); but in case (3), should it
GC> return float(ULLONG_MAX)?
GC>
GC> Initially at least, I think the answer should be "yes". Otherwise,
GC> a double cannot be converted to float unless its last (53-24)
GC> mantissa bit are all zero, which has a 1 / 536870912 probability
GC> assuming a uniform distribution.

The example of double->float conversion is just another way to say that
the answer to your question (3) should be "yes" iff we don't require
round-trip safety.

Pragmatically speaking, my preferred solution would be to not solve this
problem at all unless we really have to. So for me the immediate question
is: do we need to allow double-to-float conversions in bourn_cast<>? If we
do, then we will have to live with precision loss anyhow and so we can
accept in the case (3) as well. But if, as my hope is, we don't actually
need them right now, I would forbid them (at compile-time) and also throw
if precision is lost in any other conversion (if possible, I'd also forbid
long long to float conversions at compile time, in fact).

What do you think?
VZ

```