What's the C++ suffix for long double literals?
From the C++ Standard
The type of a floating literal is double unless explicitly specified
by a suffix. The suffixes f and F specify float, the suffixes l and L
specify long double.
It is interesting to compare with corresponding paragraph of the C Standard. In C there is used term floating constant
instead of floating literal
in C++:
4 An unsuffixed floating constant has type double. If suffixed by the letter f or F, it has type float. If suffixed by the letter l or L, it has type long double
How can the suffix for numeric literals long int and long double both be l/L?
A literal number needs to have a period or an exponent to be treated as a floating point literal constant. If it doesn't have any of these, it is treated as an integer literal constant.
C++ suffix L vs specifying long double
I am confused why not to specify long int i = 33 instead of int i = 33L?
Because that 2 statements mean 2 different things:
long int i = 33; // take constant of type int, convert it to long int and assign to i.
int i = 33L; // take constant of type long int, convert it to int and assign to i.
So you end up with variable i
of different type. Same for the double in your example.
Appending long double literal suffix to user inputs in c++
Use std::stold
to convert input text to long double. There is no need for a suffix; stold
will do it right. The suffix is needed in source code to tell the compiler what type the text represents. When you're reading from an external source the compiler isn't involved, so you have to sort out the type yourself.
Is there any difference between using floating point casts vs floating point suffixes in C and C++?
The default is double
. Assuming IEEE754 floating point, double
is a strict superset of float
, and thus you will never lose precision by not specifying f
. EDIT: this is only true when specifying values that can be represented by float
. If rounding occurs this might not be strictly true due to having rounding twice, see Eric Postpischil's answer. So you should also use the f
suffix for floats.
This example is also problematic:
long double MY_LONG_DOUBLE = (long double)3.14159265358979323846264338328;
This first gives a double
constant which is then converted to long double
. But because you started with a double
you have already lost precision that will never come back. Therefore, if you want to use full precision in long double
constants you must use the L
suffix:
long double MY_LONG_DOUBLE = 3.14159265358979323846264338328L; // L suffix
The type of a floating point literal with exponent
By default, all floating point literals, with or without an exponent part, have type double
. You can add the f
suffix to make the type float
or L
to make the type long double
.
In the case of float f = 123456e-3;
, you're initializing a float
with a double
constant, so there is the possibility of loss of precision, however this particular constant only has 6 decimal digits of precision so it should be OK.
Is there any C++ style guide that talks about numeric literal suffixes?
There is no general style guide that I've found. I use capital letters and I'm picky about using F for float literals and L for long double. I also use the appropriate suffixes for integral literals.
I assume you know what these suffixes mean: 3.14F
is a float
literal, 12.345 is a double literal, 6.6666L is a long double literal.
For integers: U
is unsigned
, L
is long
, LL
is long long
. Order between U
and the L
s doesn't matter but I always put UL
because I declare such variables unsigned long
for example.
If you assign a variable of one type a literal of another type, or supply a numeric literal of one type for function argument of another type a cast must happen. Using the proper suffix avoids this and is useful along the same lines as static_cast is useful for calling out casts. Consistent usage of numeric literal suffixes is good style and avoids numeric surprises.
People differ on whether lower or upper case is best. Pick a style that looks good to you and be consistent.
Why do you need to append an L or F after a value assigned to a C++ constant?
Floating-point constants have type double
by default in C++. Since a long double
is more precise than a double
, you may lose significant digits when long double
constants are converted to double
. To handle these constants, you need to use the L
suffix to maintain long double
precision. For example,
long double x = 8.99999999999999999;
long double y = 8.99999999999999999L;
std::cout.precision(100);
std::cout << "x=" << x << "\n";
std::cout << "y=" << y << "\n";
The output for this code on my system, where double
is 64 bits and long double
96, is
x=9
y=8.9999999999999999895916591441391574335284531116485595703125
What's happening here is that x
gets rounded before the assignment, because the constant is implicitly converted to a double
, and 8.99999999999999999
is not representable as a 64-bit floating point number. (Note that the representation as a long double
is not fully precise either. All of the digits after the first string of 9
s are an attempt to approximate the decimal number 8.99999999999999999
as closely as possible using 96 binary bits.)
In your example, there is no need for the L
constant, because 3.0
is representable precisely as either a double
or a long double
. The double
constant value is implicitly converted to a long double
without any loss of precision.
The case with F
is not so obvious. It can help with overloading, as Zan Lynx points out. I'm not sure, but it may also avoid some subtle rounding errors (i.e., it's possible that encoding as a float
will give a different result from encoding as a double
then rounding to a float
).
Related Topics
How to Use C++20's Likely/Unlikely Attribute in If-Else Statement
Why Does the Size of a Class Depends on the Order of the Member Declaration? and How
When Do I Use Fabs and When Is It Sufficient to Use Std::Abs
Visual Studio: Link:Fatal Error Lnk1181: Cannot Open Input File
What Does 'Using Std::Swap' Inside the Body of a Class Method Implementation Mean
Why Does Enable_If_T in Template Arguments Complains About Redefinitions
Why Is the Destructor Call After the Std::Move Necessary
Accessing Elements of a Cv::Mat with At<Float>(I, J). Is It (X,Y) or (Row,Col)
What's the Advantage of Using Std::Allocator Instead of New in C++
Opensouce C/C++ Math Expression Parser Library
How to Prevent Non-Specialized Template Instantiation
C++ Implementing Timed Callback Function
Dynamically Register Constructor Methods in an Abstractfactory at Compile Time Using C++ Templates
Default Values in Templates with Template Arguments ( C++ )
Copying Non Null-Terminated Unsigned Char Array to Std::String
How to Make a Variadic Is_Same
Qt Qwebenginepage::Setwebchannel() Transport Object
Why Does Unique_Ptr Take Two Template Parameters When Shared_Ptr Only Takes One