'How to detect non IEEE-754 float, and how to use them?

I'm writing classes for basic types, so that code is logically the same on multiple platforms and compilers (like int_least16_t for int). For fun! (I'm still a student.) And I read this:

float [...] Matches IEEE-754 binary32 format if supported.

And what's worse:

Floating-point types MAY support special values: , NaN or -0

Which means that float MAY be unsigned...
[edit: Yes it's difrent thing, but there is no: ",but must suport negative numbers". Yo, with out things like this in standart it may not suport normal 0...(I don't have specyfication.) see]

I know it's like with __int128, and the standard is just a standard, but still... IEEE-754 is from 1985, but some machines can be weird, and some legacy hardware doesn't have a floating unit.

As I understand, float is mandatory (not optional like int16_t), but can be in any standard, and any set of values can be possible?


Only thing we have are some macros (<cfloat>):

  • FLT_MIN, FLT_MAX - Even if FLT_MIN = IEEE-754::FLT_MIN, float can be non IEEE-754. For example float with: flipped exponent with fraction...

  • FLT_RADIX - Base system? If so, can help to write the exact value. But still, float can be 3 bit or 200 bit (in size)...

  • FLT_EPSILON - (from 1 to next) We might use it (with base) to check fraction size...

  • FLT_MANT_DIG - Is it "mantissa" digits / fraction size?

  • FLT_MAX_EXP - Exponent filled with 1... in IEEE-754, but outside can be a random number?

If float is like IEEE-754 (sign, exponent, fraction), then it's easy, but if -0 and NaN are optional then it MAY be different. Because I can't tell them apart, I can't use bit representation (in a safe manner). And if is optional, float is no longer a safe type.

The only way out I see is to add macro to compiler.

I know it's a theoretical problem, but I'm interested if there is any check possible or we all write implementation dependent code, when we use the float keyword?


Edit 2022 May 04:

I came up with this:

User eg. code:

//User eg. code:

int main()
{
   float_M a = 1f;
   float_M b = 0f;
   std::cout << a/b; //should output infinty (IEEE-754)
}

//Code:

class float_M
{
public:
#ifdef __STDC_IEC_559__
   float data;
//...
   float_M operator/(float_M x){return float_M(data/x.data);}
//...
#else
   /*union{
      float data;
      struct{//For noSign case ("absolutly catastrofic" case)
         uint_least8_t sign : 1;
         uint_least8_t exponent : 8;
         uint_least32_t fraction : 23;
      }
   }*/ //no noSign case 🙂
   float data;
//...
   float_M operator/(float_M x){return divide(this, x);}

//funtion pointer alert!
   static /*const (1*) */ float_M (*divide)(float_M a, float_M b) =
      /*std::numeric_limits<float>::is_signed ?(*/
         std::numeric_limits<float>::has_infinity ?(
            std::numeric_limits<float>::has_quiet_NaN ?(
               []{return float_M(a.data/b.data);}
            ): &_divide_noNaN
         ): &_divide_noNaN
      /*): &_divide_noSign*/
//...
#endif
}

It's ugly (have funtion pointer), but prevents unnesesery jumps at runtime. I hope c++23 will have better macros.

Also, more links:

Follow-up: Can floats not suport negative



Solution 1:[1]

In C++, the value of std::numeric_limits<T>::is_iec559 shall be true for all floating-point types T "if, and only if, the type adheres to ISO/IEC/IEEE 60559" and ISO/IEC/IEEE 60559:2011 is the same as IEEE 754-2008, so:

#include <iostream>
#include <limits>

int main() {
    std::cout << std::boolalpha << std::numeric_limits<float>::is_iec559 << '\n';
}

Note: As noted in the comments, some implementations may still report true for this constant even though their floating point types are not following the IEEE 754-2008 standard to the letter.

For example, in gcc, you can compile with the options -Ofast or -ffast-math which in turn sets a number of options which can result in incorrect output for programs that depend on an exact implementation of IEEE or ISO rules/specifications for math functions.


In C99 (and later), there are conditional feature macros, __STDC_IEC_559__ and __STDC_IEC_559_COMPLEX__, that, if available in your implementation, will tell you if it's conforming to IEC 60559:1989 / IEEE 754?1985.

#include <stdio.h>
int main(void) {
#ifdef __STDC_IEC_559__
    puts("true");
#endif
}

Note that if __STDC_IEC_559__ is not defined, it doesn't necessarily mean that the implementation doesn't use IEEE 754 floats. It could just mean that it doesn't have these conditional feature macros. One interesting note about these macros is that if you use -Ofast or -ffast-math in gcc, they will not be defined (unlike in the C++ test).

The actual revision of the IEC / IEEE standards used changed in C11 and C17/18 and in C23 (draft) there will be a number of new macros related to floating points and it (currently) refers to ISO/IEC 60559:2020 and IEEE 754-2019 which contains minor upgrades to IEC 60559:2011 / IEEE 754-2008.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1