C++ Logo

liaison

Advanced search

Re: [wg14/wg21 liaison] [isocpp-ext] Report from the recent C/C++ liaison meeting (SG22); includes new floating point types(!)

From: Jorg Brown <jorg.brown_at_[hidden]>
Date: Sun, 19 Sep 2021 18:00:39 -0700
On Sat, Sep 18, 2021 at 7:12 PM David Olsen via Ext <ext_at_[hidden]>
wrote:

> Fred Tydeman wrote:
> >> How about places where 'float' promotes to 'double' and '_Float32' does
> not promote? Such as printf()?
>
> Good point. Thanks. The proposed rules for floating-point promotion are
> the same in both languages, where float is the only thing that ever
> promotes to double. So the difference in usual arithmetic conversions
> means that:
> printf("%g", (float)1.0 + (_Float32)2.0);
> is undefined behavior in C (because the expression has type _Float32,
> which does not promote), but
> printf("%g", (float)1.0 + (std::float32_t)2.0);
> is well-formed in C++ (because the expression has type float, which does
> promote).
>
> I see this as an argument for C to change the rules so that
> float + _Float32 -> float
> Not a compelling argument by itself, but a point in favor of the change.
>

I couldn't believe this was true, but after looking it up in N2596 6.5.2.2,
I see:

If the expression that denotes the called function has a type that does not
> include a prototype,
> the integer promotions are performed on each argument, and arguments that
> have type float
> are promoted to double. These are called the default argument promotions.
> If the number of
> arguments does not equal the number of parameters, the behavior is
> undefined. If the
> function is defined with a type that includes a prototype, and either the
> prototype ends with
> an ellipsis (, ...) or the types of the argument after promotion are not
> compatible with the
> types of the parameters, the behavior is undefined.


And that's quite alarming; it means that one of these is UB and the other
is not, even though float and _Float32 will have the same representation on
most of today's compilers:

  float fa;
  printf("%g\n", fa);
  _Float32 fb;
  printf("%g\n", fb);

And it also is a pain for anyone wanting to print _Float16 values:

  _Float16 f16;
  printf("%g\n", f16); // UB
  printf("%g\n", (double)f16); // OK

It seems very much against the spirit of the automatic-float-to-double
conversion rule, for printf to work with float, but not _Float16 or _Float32
or even _Float64. Surely this was an oversight on C's part? It seems the
wording should be changed:

< arguments that have type float are promoted to double
> floating-point arguments that have less or equal range and precision than
double are promoted to double

(The "or equal" part is possibly unnecessary and reflects my imperfect
understanding of the consequences of passing _Float64 to a routine that
expects double, including whether those consequences differ from C to C++)

-- Jorg

Received on 2021-09-19 20:00:54