Is static_cast(std::nanf(“”)) well defined

2019-07-17 05:03发布

问题:

Title pretty much asks it all, but to provide a MCVE:

#include <cmath>

int main()
{
    float f = std::nanf("");
    double d = static_cast<double>(f);
    return 0;
}

Under MSVC 2017, both f and d report as nan, but that proves nothing, since it may be that the static_cast is undefined behavior.

In a similar vein, 0.0f / 0.0f produces -nan(ind) which I am going to assume is a signalling nan, does that follow the same defined / undefined rule? Ditto inf.

回答1:

This looks guaranteed by the standard, we can start with section [expr.static.cast]p4 which says:

An expression e can be explicitly converted to a type T if there is an implicit conversion sequence from e to T ...

implicit conversion sequence is covered in [over.best.ics] and we have the following:

A well-formed implicit conversion sequence is one of the following forms:
- (3.1) a standard conversion sequence,
...

and standard conversion sequence is covered in [over.ics.scs] which says:

[ Note: As described in [conv], a standard conversion sequence is either the Identity conversion by itself (that is, no conversion) or consists of one to three conversions from the other four categories. If there are two or more conversions in the sequence, the conversions are applied in the canonical order: Lvalue Transformation, Promotion or Conversion, Qualification Adjustment. — end note ]

and we have the floating point promotion case we have here covered in [conv.fpprom]p1 which says:

A prvalue of type float can be converted to a prvalue of type double. The value is unchanged.

Going the other way double to float would be a conversion and that is covered in [conv#double]p1:

A prvalue of floating-point type can be converted to a prvalue of another floating-point type. If the source value can be exactly represented in the destination type, the result of the conversion is that exact representation. If the source value is between two adjacent destination values, the result of the conversion is an implementation-defined choice of either of those values. Otherwise, the behavior is undefined.

This case depends on whether the source can be exactly represented by the destination which is not guaranteed.

The subquestion on floating point divide by zero is complicated and covered in my answer to The behaviour of floating point division by zero.



回答2:

The static_cast is merely promoting the float, which is always defined. Division by zero is undefined (even without any casting), although many implementations allow it for floating-point types according to IEEE 754 rules. Signaling NaNs are never encountered on common systems; floating-point exceptions are used instead.