Difference between long double and double in C and C++
To quote the C++ standard, §3.9.1 ¶8:
There are three floating point types: float, double, and long double. The type double provides at least as much precision as float, and the type long double provides at least as much precision as double. The set of values of the type float is a subset of the set of values of the type double; the set of values of the type double is a subset of the set of values of the type long double. The value representation of floating-point types is implementation-defined. Integral and floating types are collectively called arithmetic types. Specializations of the standard template std::numeric_limits (18.3) shall specify the maximum and minimum values of each arithmetic type for an implementation.
That is to say that double
takes at least as much memory for its representation as float
and long double
at least as much as double
. That extra memory is used for more precise representation of a number.
On x86 systems, float
is typically 4 bytes long and can store numbers as large as about 3×10³⁸ and about as small as 1.4×10⁻⁴⁵. It is an IEEE 754 single-precision number that stores about 7 decimal digits of a fractional number.
Also on x86 systems, double
is 8 bytes long and can store numbers in the IEEE 754 double-precision format, which has a much larger range and stores numbers with more precision, about 15 decimal digits. On some other platforms, double
may not be 8 bytes long and may indeed be the same as a single-precision float
.
The standard only requires that long double
is at least as precise as double
, so some compilers will simply treat long double
as if it is the same as double
. But, on most x86 chips, the 10-byte extended precision format 80-bit number is available through the CPU's floating-point unit, which provides even more precision than 64-bit double
, with about 21 decimal digits of precision.
Some compilers instead support a 16-byte (128-bit) IEEE 754 quadruple precision number format with yet more precise representations and a larger range.
What is the difference between double and long double data type in c language
What is the major difference between double and long double data type in c?
Quoting from N1570 section "6.2.5 Types" this is what the C standard says:
There are three real floating types, designated as float, double, and long
double.The set of values of the type float is a subset of the set of values of the
type double; the set of values of the type double is a subset of the set of values of the
type long double
This means that long double
is a floating point type having at least the same precision as the floating point type double
.
So maybe long double
is the same as double
. Maybe it has better precision than double
. The C standard only tells us that long double
can't have worse precision than double
.
This is further expanded in Annex E of the standard where the "minimum requirements" for double and long double is the same.
So the difference - if any - depends on your system.
Also notice that <float.h> on your system gives you information about the three floating point types on your system. For that please refer to the "5.2.4.2.2 Characteristics of floating types <float.h>" of the standard - it's too much info to be pasted into this answer.
BTW:
Instead of using pointer values you could have printed the size, like:
printf("size of double %zu\n", sizeof(double));
printf("size of long double %zu\n", sizeof(long double));
If the sizes are different then it is very likely that long double
has better precision than double
.
long double vs double
Quoting from Wikipedia:
On the x86 architecture, most compilers implement long double as the 80-bit extended precision type supported by that hardware (sometimes stored as 12 or 16 bytes to maintain data structure .
and
Compilers may also use long double for a 128-bit quadruple precision format, which is currently implemented in software.
In other words, yes, a long double
may be able to store a larger range of values than a double
. But it's completely up to the compiler.
I want to know the difference between a long double and a double
... long double is known to be more accurate than double.
No, it's really not. It may be but it's by no means guaranteed.
The difference between the two types is detailed in the standard (in this case, C++17 [basic.fundamental]/8
, though earlier iterations also have similar wording). The standard has this to say about the floating point types (my emphasis):
There are three floating-point types:
float
,double
, andlong double
.The type
double
provides at least as much precision asfloat
, and the typelong double
provides at least as much precision asdouble
.The set of values of the type
float
is a subset of the set of values of the typedouble
; the set of values of the typedouble
is a subset of the set of values of the typelong double
.The value representation of floating-point types is implementation-defined.
Since "subset" includes the possibility that the two sets are identical (it's axiomatic that A ⊂ A
), there's no actual requirement than long double
has a larger range and/or precision than double
, though it sometimes does.
If you want to figure out what the differences are in your implementation, you should be looking into the numeric_limits
class in the <limits>
header, as per the following demo program:
#include <iostream>
#include <limits>
using namespace std;
int main() {
numeric_limits<double> lim_d;
numeric_limits<long double> lim_ld;
cout << "\nmax " << lim_d.max() << " " << lim_ld.max()
<< "\nmin " << lim_d.min() << " " << lim_ld.min()
<< "\nlowest " << lim_d.lowest() << " " << lim_ld.lowest()
<< "\ndigits10 " << lim_d.digits10 << " " << lim_ld.digits10
<< '\n';
}
The output on my system is, formatted for readability:
double long double
============ =============
max 1.79769e+308 1.18973e+4932
min 2.22507e-308 3.3621 e-4932
lowest -1.79769e+308 -1.18973e+4932
digits10 15 18
You can see that my range is substantially larger for a long double
and there's also (roughly) an extra three decimal digits of precision.
In terms of what effect this can have on your code, it's difficult to say since you haven't actually provided an adequate description of what the problem is (specifically what wa
and ac
mean). However, since a long double
may have more precision and/or range than a double
, it's certainly conceivable that this may affect how your code behaves.
I should also mention that the correct format specifier for a long double
is actually %Lf
(capitalised L
) rather than %lf
. That may well be causing a problem for you since, with the test data given on the page you linked to in a comment, I get the correct result for double
/%f
and long double
/%Lf
.
But it gives different results (and a gcc
warning, for that matter) for long double
/%lf
.
Long Double vs Long Long
long long
is integer (possibly with more range than long
)long double
is floating point (possibly with more range/precision than double
)long float
does not exist.
The integer types sorted by range are
_Bool
char
orsigned char
orunsigned char
short
(orshort int
) orshort unsigned
int
orunsigned
long
(orlong int
) orlong unsigned
long long
(orlong long int
) orlong long unsigned
The floating-point types sorted by range/precision are
float
double
long double
Difference in evaluation of expression when using long long int vs double in c++
Some code to walk you through it, bottom line don't mix doubles with ints implicitly
#include <cassert>
#include <iostream>
#include <type_traits>
// typedef long long int ll; NO , use using and never use aliasing to safe a bit of typing. Aliases are there to introduce meaning not shortcuts
//using namespace std; // also NO
int main()
{
long long int lli_a = 603828039791327040;
long long int lli_b = 121645100408832000;
//double d_b = (double)lli_b; // No this is C++ don't use 'C' style casts
double d_b = static_cast<double>(lli_b);
assert(static_cast<long long int>(d_b) == lli_b); // you are in luck the double can represent your value exectly, NOT guaranteed
std::cout << "a " << lli_b - d_b << "\n"; // endl; \\0 don't use endl unless you have a good reason to flush
long long int lli_b4 = 4 * lli_b;
// use auto to show you this expression evaluates to a double!
auto lli_d_b4 = (lli_a - static_cast<long long int>(4) * d_b); // d_b is double!!! what do you want to do here? Use it as a long long int then cast it first
static_assert(std::is_same_v<double, decltype(lli_d_b4)>);
auto result_c = lli_b4 - lli_d_b4;
// result c is still a double!
static_assert(std::is_same_v<double, decltype(result_c)>);
std::cout << "c " << result_c << "\n";
// long story short don't mix types implicitly and use "C++" style cast explicitly to get the results you want
/*
cout << "b " << (lli_a - 4 * lli_b) - (lli_a - 4 * d_b) << endl; \\64
cout << "c " << (lli_a - 4 * lli_b) - (lli_a - (ll)4 * d_b) << endl; \\64
cout << "d " << (lli_a - 4 * lli_b) - (lli_a - 4 * (ll)d_b) << endl; \\0
cout << "e " << 4 * (ll)d_b - 4 * d_b << endl; \\0
cout << "f " << 4 * (ll)d_b - (ll)4 * d_b << endl; \\0
*/
return 0;
}
what is the exact range of long double in c++?
Why not ask your compiler? std::numeric_limits<long double>
is defined.
long double smallest = std::numeric_limits<long double>::min();
long double largest = std::numeric_limits<long double>::max();
long double lowest = std::numeric_limits<long double>::lowest();
std::cout << "lowest " << lowest << std::endl;
std::cout << "largest " << largest << std::endl;
std::cout << "smallest " << smallest << std::endl;
Running this code on godbolt.org with x86-64 GCC 11.2 gives me:
lowest -1.18973e+4932
largest 1.18973e+4932
smallest 3.3621e-4932
It might vary for your platform, of course.
Difference in the amount of decimal numbers between double and long double
double
- 15 decimal places
long double
- 19 decimal places (on systems where 80-bit format is used)
80-bit is the most common format, but is not available on all systems.
https://en.cppreference.com/w/c/language/arithmetic_types#Real_floating_types
https://www.tutorialspoint.com/cprogramming/c_data_types.htm
Related Topics
Does Std::Array<> Guarantee Allocation on the Stack Only
Understanding Boost::Disjoint_Sets
How to Determine Programmatically If an Expression Is Rvalue or Lvalue in C++
Lambdas Require Capturing 'This' to Call Static Member Function
Getting a Bunch of Crosses Initialization Error
Why Does Enumwindows Return More Windows Than I Expected
Initialize Std::Array with a Range (Pair of Iterators)
This Case of Template Function Overloading Eludes My Understanding
Automatic Copy Files to Output During Application Building
Why Vector Access Operators Are Not Specified as Noexcept
Why Does Initializing an Extern Variable Inside a Function Give an Error
Can You Use Keyword Explicit to Prevent Automatic Conversion of Method Parameters
Preventing Non-Const Lvalues from Resolving to Rvalue Reference Instead of Const Lvalue Reference