3

As many programmers know there are several floating-point types in C. So far I know float, double and long double but I'm not quite sure they are all of them, cause I found several definitions like __DEC32_MAX__. At first I thought that is another name for __FLT_MAX__ but when I tried to print it, I realized that it's different (as in below):

#include <stdio.h>

void main(void)
{
    __mingw_printf("flt    value: %e, size: %d\n", __FLT_MAX__, sizeof(__FLT_MAX__));
    __mingw_printf("dbl    value: %e, size: %d\n", __DBL_MAX__, sizeof(__DBL_MAX__));
    __mingw_printf("ldbl   value: %e, size: %d\n", __LDBL_MAX__, sizeof(__LDBL_MAX__));
    __mingw_printf("dec32  value: %e, size: %d\n", __DEC32_MAX__, sizeof(__DEC32_MAX__));
    __mingw_printf("dec64  value: %e, size: %d\n", __DEC64_MAX__, sizeof(__DEC64_MAX__));
    __mingw_printf("dec128 value: %e, size: %d\n", __DEC128_MAX__, sizeof(__DEC128_MAX__));
}

/* output:
flt    value: 3.402823e+038, size: 4
dbl    value: 1.797693e+308, size: 8
ldbl   value: 3.237664e-317, size: 16
dec32  value: 9.944455e-315, size: 4
dec64  value: 9.089022e+269, size: 8
dec128 value: 3.237656e-317, size: 16
*/

What are __DEC__* s?
Are there any other floating-point types that I don't know?

phuclv
  • 37,963
  • 15
  • 156
  • 475
Jenny
  • 33
  • 3
  • 1
    Standard C have the three you list: `float`, `double` and `long double`. And on some systems `double` and `long double` might be the same. – Some programmer dude Aug 27 '22 at 07:29
  • 1
    By the way, to print a `long double` value you should use the format specifier `%Le`. Mismatching format specifier and argument type leads to *undefined behavior*. And to print a `size_t` (which is the type of the result of `sizeof`) you should use `%zu`. – Some programmer dude Aug 27 '22 at 07:31
  • 2
    And talking about `printf`, why are you using the non-standard `__mingw_printf` instead of the standard `printf`? Similarly with the non-standard constants like `__FLT_MAX__` instead of the standard `FLT_MAX`? What resources are you using to learn C? – Some programmer dude Aug 27 '22 at 07:34

3 Answers3

5

There are only 3 real floating-point types in C before C23: float, double and long double, which can use arbitrary base for the significand like decimal or octal although nowadays it's most likely binary. Some older systems use hexadecimal floating-point types. Each of the real floating types can be combined with the _Complex or _Imaginary keyword to make complex floating types

C23 added 3 more real floating-point types: _Decimal32, _Decimal64, and _Decimal128, all are decimal types

Anything else if you see would be compiler extensions or internal compiler things. Those would be prefixed with __ because identifiers beginning with double underscores are reserved for implementations. __mingw_printf, __DBL_MAX__, __DEC64_MAX__... are all internal to the implementation and you aren't supposed to use them directly. Use FLT_MAX instead of __FLT_MAX__

In fact before C23 there's a decimal floating extension in GCC

As an extension, GNU C supports decimal floating types as defined in the N1312 draft of ISO/IEC WDTR24732. Support for decimal floating types in GCC will evolve as the draft technical report changes. Calling conventions for any target might also change. Not all targets support decimal floating types.

The decimal floating types are _Decimal32, _Decimal64, and _Decimal128. They use a radix of ten, unlike the floating types float, double, and long double whose radix is not specified by the C standard but is usually two.

6.14 Decimal Floating Types

Since mingw is a GCC port, it also supports that decimal floating extension. Typically in float.h the standard constants would be defined as the implementation-specific constants, for example

#define LDBL_MAX   __LDBL_MAX__
#define DEC128_MAX __DEC128_MAX__
phuclv
  • 37,963
  • 15
  • 156
  • 475
3

The decimal types are very special, very interesting, and very much not standard (yet). They use an internal fraction representation which is based on base 10, not base 2. See in particular IEEE 754-2008.

So all of the important, unfortunate, tiresome arguments about 0.1 not being exactly representable, about 0.1 + 0.2 not exactly equaling 0.3, go away, and almost miraculously computer floating point can behave just like the decimal floating point we're all used to! But these types, and the printf support they'd require, are not standard, popular, or well known — yet.

In IEEE 754-2008, the two principal decimal types are decimal32 and decimal64, which are the decimal counterparts to our familiar binary float and double. There is also decimal128 analogous to long double.


Footnote: Strictly speaking, it's not quite correct to say that decimal32 and the rest are the "decimal counterparts" to our "familiar binary" floating-point types like float and double. The new decimal types are, AFAIK, indeed guaranteed to be decimal. But the traditional types float, double, and long double were not guaranteed to be binary. They usually were, on virtually every machine you're ever likely to use, but they could also be decimal, on one of the rare old machines that implemented floating-point natively and only in decimal. On such a machine, you'd notice that FLT_RADIX from <float.h> was 10.

Steve Summit
  • 45,437
  • 7
  • 70
  • 103
2

Some specific uses require small floats like: float8 and float16 and bifloat It is used mainly in the DSP, AI and graphics applications. Many hardware architectures support at least some of them (for example bifloat AVX-512 BF16, ARM-V8.8, AMD ROCm, CUDA and some more).

There are also big float formats like float128. Example hardware: VSX in PowerPC.

Those floats are not supported directly by the standard C. Some compilers support it as an extension.

0___________
  • 60,014
  • 4
  • 34
  • 74