In such a program in C

double x = 1; x %= 1.; 

I get the error message http://ideone.com/dDurEH

invalid operands to binary% (have 'double' and 'long double' )

from which it follows that the expression 1. has the type long double .

The same code, but the pluses just show double http://ideone.com/nd49YK :

invalid operands of types 'double' and 'double' to binary 'operator%'

And such a check on the pros, too, for double http://ideone.com/HCw0GG :

 auto x = 1.; cout << sizeof (double) << ' ' // 8 << sizeof (long double) << ' ' // 12 << sizeof x << ' ' // 8 << sizeof 1. << endl; // 8 

It turns out, With ++ deduces the type double , but not long double .

So, is this one of the differences between C and C ++, or is it a compiler jamb?
What is the correct type for a constant 1. and does it depend on the language?

  • I declare double on arduino always with a dot. I think it's worth trying double x = 1 .; - ilyaplot
  • @ilyaplot, and how does this relate to the question? - Qwertiy
  • one
    In the pros 1. - just double . In this - it is necessary to dig a standard. Apparently the compiler is naughty . - αλεχολυτ
  • @alexolut, so I used it to check the advantages, that I remember that double. - Qwertiy
  • 2
    The C Complete Reference Book (C in a Nutshell) clearly states that without suffixes is just double . So that was a long double , you need a suffix - 1.L - Harry

3 answers 3

A constant of type 1. has a double type in both C ++ and C.

  • C

    6.4.4.2/4: An unsuffixed floating constant has type double . If suffixed by letter for F , it has type float . If suffixed by letter or L , it has type long double .

  • C ++

    2.14.4 / 1: It is not possible to explicitly specify the type of suffix.

The compiler used on ideone.com is version 5.1.1 20150711 . So it may make sense to drive it locally, if anyone has the opportunity. A similar compiler on goodbolt (5.1) gives an error with the correct types :

 error: invalid operands of types 'double' and 'double' to binary 'operator%' error: in evaluation of 'operator%=(double, double)' 

A possible reason is the FLT_EVAL_METHOD value, which sets the calculation accuracy for internal operations. For ideone, this value is 2 , because 32-bit compiler is used :

For gcc, FLT_EVAL_METHOD == 2 is the default on 32 bit x86

Those. All floating point calculations are based on the type long double .

Although, in truth, this should not affect the type of a real constant.

As it turned out, the g ++ compiler can change the value of FLT_EVAL_METHOD from 0 to 2 to 64 bit by adding the -mfpmath=387 key:

 #include <stdio.h> #include <float.h> int main() { // 1 % 1.; printf( "%d\n", FLT_EVAL_METHOD); } 

Result:

 2 

In this case, the error message for the second argument also displays the type long double as well as the initial one on ideone (for 32 bit):

 invalid operands to binary % (have 'int' and 'long double') 

For clang, another key is needed: -mno-sse . In this case, the diagnostic message for both types displays a double :

 invalid operands to binary expression ('double' and 'double') 

At the same time, the first, as it seems to me, should nevertheless remain an int .

Summarizing, we can say that both compilers in diagnostic messages have problems with the derivation of the original type of operands.

  • It is time for them to update the compiler - some bugs ... - Qwertiy
  • gcc 5.2.1 20151010 also gives out the right types - iksuy
  • @Qwertiy may not be enough for the compiler. See amended answer. - αλεχολυτ
  • But sizeof showed 8, that is, if the program is compiled, then there is no long double . How else can you check? - Qwertiy
  • 2
    @Qwertiy Sorry, did not understand the comment. The type of the constant at the language level does not change, i.e. 1. it is double anyway. But when this value falls into the FPU bins, its type is FLT_EVAL_METHOD to long double in accordance with FLT_EVAL_METHOD . And this long double apparently and prolazit in the diagnostic message. In general, it makes sense to find another compiler where FLT_EVAL_METHOD == 2 and look at its errors. It seems to me that gcc here simply brings out its computational "offal". - αλεχολυτ

The constant with a floating point 1. is of type double .

Similar error messages like this

invalid operands to binary% (have 'double' and 'long double'

related to how the C compiler converts floating-point operands in expressions. For example, the compiler can convert floating-point operands to a format whose value range and accuracy exceed the corresponding value range and the accuracy of the original floating point type. This is done in order to obtain more accurate results in the process of evaluating expressions and their composite subexpressions.

From standard C (5.2.4.2.2 Characteristics of oating types <float.h> )

9 Except for assignment and precision, can be greater than required by the type . The value of FLT_EVAL_METHOD: 24)

-1 indeterminable; 0 evaluate all types of operations;

For each type of double type;

2 evaluate all long double type .

All other negative values ​​for FLT_EVAL_METHOD characterize implementation-de-ned behavior.

If you include a header, where the name FLT_EVAL_METHOD defined, you can get the following result

 #include <stdio.h> #include <float.h> int main(void) { printf( "%d\n", FLT_EVAL_METHOD ); return 0; } 

Output to console:

 2 

As follows from the above quote from the C standard, this means that the constants will be converted to the type long double .

If the header file <float.h> not included, however, the compiler apparently uses this default option to evaluate floating-point expressions.

    I decided to check through sizeof http://ideone.com/r54ZSs :

     #include <stdio.h> int main() { printf("%d %d %d", sizeof (double), sizeof (long double), sizeof 1.); return 0; } 

    Got 8 12 8. That is, this is a regular double .

    Apparently, some error crept into the error analysis, because only there he gets a different type of http://ideone.com/45lztk :

     int main() { int x = 1; x %= 1.; // error: invalid operands to binary % (have 'int' and 'long double') x %= (double)1.; // error: invalid operands to binary % (have 'int' and 'double') return 0; }