0

For getting better decimal precision, I decided to use "long double" in my C++ code. But even the following code:

long double a=5;
long double b=0.54645;
long double c=a*b;
printf("%Lf\n", c);

generates a -0.00000 on my computer. I think it's the compiler's fault,as the answers point out.

The motivation was: I am dealing with a lot of doubles, multiplying them and then adding the results. While adding, I need to have the final answer to be less than 1e-6 off from the correct answer. But using doubles achieves me a wrong answer due to precision issues maybe. By wrong answer, I mean more than 1e-6 off. SO, I decided to use long doubles.

But another fact has grabbed my attention, which is: When I used long doubles and run my program on an online IDE(ideone.com), it is still rounding off like double, and giving me the less precise answer. What should be done to avoid this?

  • What does `std::cout` give you? –  Nov 10 '14 at 16:11
  • It gives me a -6.00905e-083, which as you can see is also not correct. –  Nov 10 '14 at 16:14
  • What do you get if you `printf` all of the values (i.e. `a`, `b` and `c`)? – Evil Dog Pie Nov 10 '14 at 16:16
  • Could you expand the few lines of code to make it a self contained program that shows this error. Include the compilation command as well. –  Nov 10 '14 at 16:16
  • Using printf for all three gives me -0.0000000 for all three: a,b,c. –  Nov 10 '14 at 16:23
  • What compiler are you using? – Evil Dog Pie Nov 10 '14 at 16:25
  • I am using MinGW g++ compiler. –  Nov 10 '14 at 16:26
  • Are the results with or without the `freopen` function? And what's your compilation command? –  Nov 10 '14 at 16:28
  • They are with the freopen function. I compiled the same code on ideone.com (of course without the freopen there) and there this works fine. By compilation command what do you mean? –  Nov 10 '14 at 16:32
  • Humour me for a second. Drop the `long` from `long double` and have a look at those results; don't forget to change the `printf` formatter too. On many compilers `double` and `long double` are the same size. – Bathsheba Nov 10 '14 at 16:34
  • @MikeofSST The `%Lf` will reformat the variable to avoid scientific notation and use a fixed number of decimal places. As noted above it is a negative number that is rounded to 0 at that precision. – Degustaf Nov 10 '14 at 16:35
  • Compilation command: how do you compile the code? On the command line (then what's the command?) or from within an IDE (then what are the options/flags etc you're using)? –  Nov 10 '14 at 16:35
  • At least then, remove the `freopen` functions (and all the unnecessary header includes and the macros); the simpler/shorter, the easier to find the problem. –  Nov 10 '14 at 16:37
  • @Bathsheba Just the double works fine. –  Nov 10 '14 at 16:38
  • @Evert It just gives the same -0.000000. And my compilation line is: g++ "temp.cpp" -o "temp" –  Nov 10 '14 at 16:41
  • @MikeofSST So what should I do to make it work? –  Nov 10 '14 at 16:42
  • 2
    @MikeofSST: No, negative zero and NaN are not at all the same thing. – Keith Thompson Nov 10 '14 at 16:42
  • @Degustaf 5.0 * 0.54654 won't give a very small negative number. (I can't reproduce his problem. Of course, I didn't bother to include all of the unnecessary includes, just ``.) – James Kanze Nov 10 '14 at 16:45
  • 4
    Please see [this answer](http://stackoverflow.com/a/14988103/3581917), which explains that the standard MinGW `printf` **does not** support long double arguments in `printf`. – Evil Dog Pie Nov 10 '14 at 16:49
  • @ParamjitSingh: In which case it is a compiler bug. Your code is fine and %Lf *is* the correct specifier for a `long double`. If on your platform `sizeof(double) == sizeof(long double)` then the point is moot. Change your code, and eventually, your compiler! – Bathsheba Nov 10 '14 at 16:50
  • @JamesKanze the statement was made that `cout` provided a value of -6.00905e-083, which would be rounded to -0. My point was that we shouldn't be thinking about this as a NaN error. A (wrong) number is generated. – Degustaf Nov 10 '14 at 16:51
  • I agree with @Degustaf –  Nov 10 '14 at 16:53
  • @Degustaf Agreed. We should be thinking about why `cout` displayed `-6.00905e-083` instead of `2,7327`. (Also curious: why an exponent of `083`? It should be just `83`, according to the standard.) – James Kanze Nov 10 '14 at 16:54
  • @KeithThompson Thanks for pointing that out. Please downvote my comment. – Evil Dog Pie Nov 10 '14 at 16:55
  • When two doubles (or long doubles) are added or multipled, the two answers should not be rounded off, right, atleast till say 15 places of decimal. So why am I getting the rounded off result? My requirements should be ideally met by double as well. –  Nov 10 '14 at 16:59
  • possible duplicate of [printf and long double](http://stackoverflow.com/questions/4089174/printf-and-long-double) – Keith Thompson Nov 10 '14 at 17:01
  • @MikeofSST: Comments can't be downvoted. You can delete your comment if you like. – Keith Thompson Nov 10 '14 at 17:03
  • Your original question was about the zero results you were getting on your system. You've now edited the question to ask about imprecise results you're getting with ideone.com. That's a separate question (likely a duplicate; there are *a lot* of questions about floating-point loss of precision). – Keith Thompson Nov 10 '14 at 17:09
  • So, I can use the comments. Right? –  Nov 10 '14 at 17:11

1 Answers1

4

Your program works correctly on my system (after I remove the irrelevant cruft); the output is:

5.000000
0.546450
2.732250

If I change the %Lf formats to %f (which is incorrect), I get 0.00000.

I think you're using MinGW, a C implementation for Windows that uses the gcc compiler and Microsoft's runtime library. (If you're not using MinGW, the rest of this answer is incorrect.)

MinGW has a known bug: it doesn't handle long double consistently. gcc treats long double a wider type with more range and precision than double; Microsoft's runtime library, if I recall correctly, treats it as a type with the same size, range, and precision as double.

Either representation is perfectly valid, but combining the two in a single implementation creates this kind of bug. This not a bug in gcc or in Microsoft's implementation; it's a bug in the way MinGW has combined them.

You can perform computations using long double and get consistent results, as long as you don't call any library functions. But if you try to print a long double using Microsoft's printf you'll get inconsistent results.

Presumably the same problem applies to the functions in <math.h>.

If you're using MinGW, it's probably best just to avoid using long double, and to settle for the lesser range and precision of double (which is the same range and precision you'd get with long double in a pure Microsoft implementation anyway).


Incidentally, your self contained program is much bigger than it needs to be; the vast majority of it is completely irrelevant to the problem you're asking about. And the freopen calls prevent the output from appearing. You have a comment:

//Remember to remove freopen

but you left the calls in place.

Here's a smaller version:

#include <cstdio>
int main()
{
    long double a=5;
    long double b=0.54645;
    long double c=a*b;
    printf("%Lf\n", a);
    printf("%Lf\n", b);
    printf("%Lf\n", c);
    return 0;
}
Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
  • I know that a lot of stuff here is irrelevant, but I don't see how the includes, and macros make a difference. On my computer, I use freopen because I like doing IO via text files. The result should be the same. My comment is there when I have to send code to someone else (who might not be using freopen). Your smaller version also doesn't work on my computer. I think it is the MinGw issue. Thanks for the answer. –  Nov 10 '14 at 17:04
  • You've failed to answer his question: "When I used long doubles and run my program on an online IDE(ideone.com), it is still rounding off like double, and giving me the less precise answer. What should be done to avoid this?". – Jerry Coffin Nov 10 '14 at 17:07
  • @ParamjitSingh: It made a difference for me because your program produced no visible output when I compiled and ran it on my system. It didn't occur to me until later to look for an `Output.txt` file. Redirecting stdio to a file just clouds the issue. – Keith Thompson Nov 10 '14 at 17:10
  • @JerryCoffin: The question about the behavior on ideone.com was edited in later. The original question was about the MinGW behavior, and that's the one I answered (and later voted to close as a duplicate). – Keith Thompson Nov 10 '14 at 17:11
  • @KeithThompson: ...and yet you leave a comment on my answer as if there was something wrong with it because it answered that question instead of the one none of us should have answered, as even you admit it's a dupe. – Jerry Coffin Nov 10 '14 at 17:14
  • In my opinion you didn't answer that question. If you think you did, why did you delete your own answer? – Keith Thompson Nov 10 '14 at 17:18
  • @JerryCoffin: Just out of curiosity, did you downvote my answer? – Keith Thompson Nov 10 '14 at 17:19
  • @KeithThompson: Yes--the only question it answers is one that you know is a dupe, therefore it doesn't seem to contribute anything new or useful. As to deleting my answer: if everybody feels obliged to down-vote without even bothering to read the question it answers, then screw it. – Jerry Coffin Nov 10 '14 at 17:20