2009-09-04 1 views
12

Я просмотрел несколько мест в Интернете и не могу найти подходящего объяснения относительно , почему следует добавить F или L после значения, назначенного константе C++. Например:Зачем вам добавлять L или F после значения, назначенного константе C++?

const long double MYCONSTANT = 3.0000000L; 

Может кто-нибудь объяснить, почему это необходимо? Разве декларация типа не означает, что значение, присвоенное MYCONSTANT, длинное двойное? В чем разница между приведенной выше линией и

const long double MYCONSTANT = 3.0000000;  // no 'L' appended 

Whew!

+0

C++ FAQ: [Что такое суффиксы для числовых литералов?] (Http://www.parashift.com/c++-faq-lite/numeric-literal-suffixes.html) – legends2k

+0

Возможный дубликат [что такое причина для явного объявления L или UL для длинных значений] (https://stackoverflow.com/questions/13134956/what-is-the-reason-for-explicitly-declaring-l-or-ul-for-long-values) –

ответ

13

Константы с плавающей запятой имеют тип double по умолчанию в C++. Поскольку long double более точен, чем double, вы можете потерять значительные цифры, когда long double константы преобразуются в double. Чтобы обрабатывать эти константы, вам необходимо использовать суффикс L для поддержания точности long double. Например,

long double x = 8.99999999999999999; 
long double y = 8.99999999999999999L; 
std::cout.precision(100); 
std::cout << "x=" << x << "\n"; 
std::cout << "y=" << y << "\n"; 

Выход для этого кода в моей системе, где double составляет 64 бита и long double 96, является

x=9 
y=8.9999999999999999895916591441391574335284531116485595703125 

То, что здесь происходит, что x получает округляется до назначения, потому что константа неявно преобразуется в double, а 8.99999999999999999 не представляется в виде 64-битного числа с плавающей запятой. (Обратите внимание, что представление в виде long double не полностью точное либо. Все цифр после первой строки 9 с являются попыткой приблизить десятичное число 8.99999999999999999 как можно ближе с использованием 96 двоичных разрядов.)

В вашем Например, нет необходимости в константе L, так как 3.0 представляется точно как либо double, либо long double. Постоянное значение double неявно преобразуется в long double без какой-либо потери точности.

Корпус с F не так очевиден. Это может помочь с перегрузкой, как указывает Зан Линкс. Я не уверен, но он также может избежать некоторых тонких ошибок округления (то есть, возможно, что кодирование как float даст другой результат от кодирования как double, затем округление до float).

+1

Но компилятор может это исправить из декларации. Вам не нужно ставить «int a = 1i» или «char a = 1c», если я говорю «float a = 1.0» или «double a = 1.0», это должно быть довольно очевидно, я имею в виду float/double соответственно. –

+0

Вы просите компилятор сделать вывод типа, который он не делает, даже для целочисленных констант. По умолчанию константы Integer являются int. Компилятор не предупреждает вас о назначении константы int char, если она находится в диапазоне символов. Он может попытаться предупредить константы с плавающей запятой, но я полагаю, что правила преобразования слишком сложны (целые границы намного проще). –

+2

Вы можете написать все значения char как int литералы. Проблема с литературными литералами точки зрения состоит в том, что они находятся в десятичной, а не двоичной форме. Поэтому даже «0.1» не вписывается в длинный двойной. Но, учитывая эти ограничения, «0.1L» является лучшим приближением, а затем «0.1». – MSalters

13

Нет, декларация не означает, что инициализатор имеет определенный тип. Тип инициализации тот же, независимо от того, какой тип инициализируется переменной.

Итак, если вы инициализируете long double, но используйте для настройки, double, это было бы довольно глупо. Используя суффикс L, вы говорите, что это литерал с плавающей точкой типа long double. Добавленный к целочисленному литералу, он сказал бы, что тип имеет long int.

+2

Обратите внимание, что для целых чисел существуют другие правила, если у вас есть шестнадцатеричный или восьмеричный литерал. Без какого-либо суффикса шестнадцатеричный или восьмеричный литерал также может стать неподписанным, если его значение не соответствует соответствующему подписанному типу (int, unsigned int, long, unsigned long). В C++ 03 добавление L также даст десятичные литералы беззнакового типа в зависимости от значения и диапазона типов (long, unsigned long). Однако в C++ 0x десятичные литералы всегда будут иметь тип подписи, независимо от того, был ли добавлен суффикс (длинный, длинный). Довольно смущаю, я думаю ... –

4

Когда есть буквальное значение, оно считается определенного типа. 3.0 считается двойным 3 считается int. 3.0F превращает его в float вместо двойного 3.0L, что делает его длинным двойным, а не двойным. 3L - это длинный int вместо int.

Обратите внимание, что хотя бы в g ++ и VS08 оба ваших примера работают нормально.

1

Ваш пример не нуждается в этом, но самая большая причина, по которой я знаю, использовать явные типы для литеральных значений, заключается в том, чтобы вызывать правильную перегрузку функции.

Это может сделать большую разницу в конструкторах, операторские перегрузках и т.д.

Иногда нет удобного способа получить буквальную в правильный тип, так что вы должны использовать static_cast или положить конструктор вокруг буквальный.

 Смежные вопросы

  • Нет связанных вопросов^_^