The precision of the long double output is not correct. What might be wrong?
Asked Answered
F

2

1

I have a long double constant that I am setting either as const or not-const. It is longer (40 digits) than the precision of a long double on my test workstation (19 digits).

When I print it out, it no longer is displayed at 19 digits of precision, but at 16.

Here is the code I am testing:

#include <iostream>
#include <iomanip>
#include <limits>
#include <cstdio>

int main ()
{
    const long double constLog2 = 0.6931471805599453094172321214581765680755;
    long double log2 = 0.6931471805599453094172321214581765680755;    

    std::cout << std::numeric_limits<long double>::digits10 + 1 << std::endl;
    std::cout << "const via cout: " << std::setprecision(19) << constLog2 << std::endl;
    std::cout << "non-const via cout: " << std::setprecision(19) << log2 << std::endl;
    std::fprintf(stdout, "const via printf: %.19Lf\n", constLog2);
    std::fprintf(stdout, "non-const via printf: %.19Lf\n", log2);

    return 0;
}

Compile:

$ g++ -Wall precisionTest.cpp

Output:

$ ./a.out
19
const via cout: 0.6931471805599452862
non-const via cout: 0.6931471805599452862
const via printf: 0.6931471805599452862
non-const via printf: 0.6931471805599452862

I would expect 0.6931471805599453094 but instead get 0.6931471805599452862.

Is there a reason that the 19 digits of precision are cut to 16 digits?

Here is my environment:

$ gcc --version
i686-apple-darwin9-g++-4.0.1 (GCC) 4.0.1 (Apple Inc. build 5490)

I am seeing the same problem with other versions of gcc, e.g.:

$ gcc --version
g++ (GCC) 3.4.6 20060404 (Red Hat 3.4.6-10)

I can look into NTL or other libraries but I'm curious what is causing this. Thanks for your insight.

Fencesitter answered 26/3, 2009 at 0:54 Comment(3)
If you really need this much precision, you should look into a separate libraryBlowhard
That's fine, and I probably will, but I'd like to know why I'm getting 16 digits instead of the 19 that <limits> "promises".Fencesitter
Have you actually tried using a long double literal? like suffixing it with L ?Marten
M
10

I get this output:

19
const via cout: 0.6931471805599453094
non-const via cout: 0.6931471805599453094
const via printf: 0.6931471805599453094
non-const via printf: 0.6931471805599453094

But i'm using long double literals instead of double literals:

const long double constLog2 = 0.6931471805599453094172321214581765680755L;
long double log2 = 0.6931471805599453094172321214581765680755L;    
Marten answered 26/3, 2009 at 1:3 Comment(1)
With an L at the end of the literal, for those who didn't notice. ;)Incisure
C
4

There are some subtle issues relating to hardware platforms and compile options that might be of interest:

These `-m' options are defined for the i386 and x86-64 family of computers:

-m96bit-long-double

-m128bit-long-double

These switches control the size of long double type. The i386 application binary interface specifies the size to be 96 bits, so -m96bit-long-double is the default in 32 bit mode. Modern architectures (Pentium and newer) would prefer long double to be aligned to an 8 or 16 byte boundary. In arrays or structures conforming to the ABI, this would not be possible. So specifying a -m128bit-long-double will align long double to a 16 byte boundary by padding the long double with an additional 32 bit zero.

In the x86-64 compiler, -m128bit-long-double is the default choice as its ABI specifies that long double is to be aligned on 16 byte boundary.

Notice that neither of these options enable any extra precision over the x87 standard of 80 bits for a long double.

Warning: if you override the default value for your target ABI, the structures and arrays containing long double variables will change their size as well as function calling convention for function taking long double will be modified. Hence they will not be binary compatible with arrays or structures in code compiled without that switch.

Coextend answered 26/3, 2009 at 1:13 Comment(1)
In what situations adding 16 bits of padding to an 80-bit number help anything? On a 32-bit bus, a halfword-aligned 80-bit number is going to span three words regardless of whether it starts on an even or odd halfword boundary. On a 64-bit bus, it's going to span two bus-words regardless of the halfword on which starts. On a 128-bit or larger bus, the probability of a randomly-placed item spanning bus-words will be the same for any alignment between 16 and 64 bits. Is padding designed for non-x86 systems?Harim

© 2022 - 2024 — McMap. All rights reserved.