Страницы

Поиск по вопросам

пятница, 5 октября 2018 г.

Какого типа `1.`?

В такой программе на Си
double x = 1; x %= 1.;
получаю сообщение об ошибке http://ideone.com/dDurEH
invalid operands to binary % (have 'double' and 'long double')
из которого следует, что выражение 1. имеет тип long double
Тот же код, но на плюсах показывает просто double http://ideone.com/nd49YK
invalid operands of types 'double' and 'double' to binary 'operator%'
Да и такая проверка на плюсах тоже за double http://ideone.com/HCw0GG
auto x = 1.;
cout << sizeof (double) << ' ' // 8 << sizeof (long double) << ' ' // 12 << sizeof x << ' ' // 8 << sizeof 1. << endl; // 8
Получается, С++ выводит тип double, а не long double
Итак, это одни из различий Си и Си++ или же косяк компилятора? Какой правильный тип у константы 1. и зависит ли он от языка?


Ответ

Константа вида 1. имеет тип double как в C++, так и в C.
C
6.4.4.2/4: An unsuffixed floating constant has type double. If suffixed by the letter for F, it has type float. If suffixed by the letter l or L, it has type long double C++
2.14.4/1: The type of a floating literal is double unless explicitly specified by a suffix.
Компилятор, используемый на ideone.com имеет версию 5.1.1 20150711. Так что может иметь смысл погонять её локально, если у кого есть возможность. Похожий компилятор на goodbolt (5.1) выдает ошибку с правильными типами
error: invalid operands of types 'double' and 'double' to binary 'operator%' error: in evaluation of 'operator%=(double, double)'
Возможная причина кроется в значении FLT_EVAL_METHOD, которое задает точность вычислений для внутренних операций. Для ideone это значение равно 2, т.к. используется 32-битный компилятор
For gcc, FLT_EVAL_METHOD == 2 is the default on 32 bit x86
Т.е. все вычисления с плавающей точкой опираются на тип long double
Хотя, по правде говоря, это и не должно влиять на тип вещественной константы.
Как оказалось, изменить значение FLT_EVAL_METHOD с 0 на 2 на 64 bit компиляторе g++ можно путём добавления ключа -mfpmath=387
#include #include
int main() { // 1 % 1.; printf( "%d
", FLT_EVAL_METHOD); }
Результат:
2
В этом случае сообщение об ошибке для второго аргумента также выводит тип long double как и исходное на ideone (для 32 bit):
invalid operands to binary % (have 'int' and 'long double')
Для clang нужен другой ключ: -mno-sse. При этом диагностическое сообщение уже для обоих типов выводит double
invalid operands to binary expression ('double' and 'double')
При этом первый, как мне кажется, должен всё же был остаться int.
Подводя итог, можно сказать, что оба компилятора в диагностических сообщениях имеют проблемы с выводом исходного типа операндов.

Комментариев нет:

Отправить комментарий