0

For any algorithmic problem, an error of 10-6 is allowed.

I declared a long double as a variable in my first solution and got a WA.

But, when I declared a variable as double, I got an AC.

I want to know why this decision was made because long double is known to be more accurate than double. I have not changed anything except variables, output methods.

Here is my code:

#include <iostream>
#include <string>
#include <cmath>
#include <vector>
#include <queue>
#include <deque>
#include <algorithm>

using namespace std;

#define pi 3.141592653589

int main() {
    double x;
    double y;
    double r = 0.0;
    int n;
    double len;
    double ans = 0.0;
    deque<double> dq;

    cin >> n;
    for (int i = 0; i < n; i++) {
        cin >> x >> y;
        len = sqrt(x* x + y * y);
        if (len > r) {
            r = len;
            dq.clear();
            if ((x > 0 && y <= 0) || (x >= 0 && y < 0))
                dq.push_back(360.0 + (90 + atan2(x, y) * 180 * (-1) / pi));
            else
                dq.push_back(90+atan2(x, y) * 180 * (-1) / pi);
        } else if (r == len) {
            if ((x > 0 && y <= 0) || (x >= 0 && y < 0))
                dq.push_back(360 + (90 + atan2(x, y) * 180 * (-1) / pi));
            else
                dq.push_back(90+atan2(x, y) * 180 * (-1) / pi);
        }
    }
    sort(dq.begin(), dq.end());
    if (dq.size() >= 2) {
        for (int i = 0; i < dq.size() - 1; i++) {
            ans = max(ans, dq[i + 1] - dq[i]);
        }
        ans = max(ans, 360 - dq.back() + dq.front());
        printf("%0.6f", ans);
    }
    else
        cout << "360.000000";
}

The only changes I made were:

  • changing the double to long double; and
  • changing the printf format specifier from f to lf.
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
진민수
  • 55
  • 3

2 Answers2

4

... 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, 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.

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.

Community
  • 1
  • 1
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • Just a nit about presentation: in general it's better to cite the **tag** for a section of the standard rather than the section number and title. The tag doesn't change from version to version. So "[basic.fundamental]/8" rather than "6.9.1 Fundamental types /8". I don't have C++17 handy, but in C++14, [basic.fundamental] is 3.9.1. – Pete Becker Nov 01 '18 at 15:47
  • I'll take that on board, @Peter, it's good advice. It's going to take *quite* a lot of effort to go and change all my previous answers :-) but I'll do it if and when they need updating, and for all future answers as well. – paxdiablo Nov 02 '18 at 00:45
  • thanks for your answer. As you said, if I do not get an error when I use a double, I should not get any errors when I use a long double. However, there are no errors in the double, and there are errors in the long double. I think that this would have happened because I did various arithmetic operations. So I want to know if there is a difference between the operation of the variables of double and long double. – 진민수 Nov 07 '18 at 02:26
  • @진민수, then you're going to need to provide more details, specifically code that shows the problem. Until then, we can only suggest/surmise. In terms of your specific question in the previous comment: yes, there is a difference. Not so much necessarily in the *way* things are done but certainly with the *possibly* expanded range and precision of the `long double` type. – paxdiablo Nov 07 '18 at 03:28
  • To explain the problem briefly, if I enter a point on the coordinate plane, i find the longest distance from the origin and find that the points are straight lines from the origin. When I select two straight lines out of these straight lines, I find the angle of the two straight lines with the largest angle. Source: https://www.acmicpc.net/problem/16115 – 진민수 Nov 08 '18 at 02:46
  • @paxdiablo #include #include #include #include #include #include #include using namespace std; #define pi 3.141592653589 int main() { double x; double y; double r = 0.0; int n; double len; double ans = 0.0; deque dq; cin >> n; for (int i = 0; i < n; i++) { cin >> x >> y; len = sqrt(x* x + y * y); if (len > r) { r = len; dq.clear(); if ((x > 0 && y <= 0) || (x >= 0 && y < 0)) dq.push_back(360.0 + (90 + atan2(x, y) * 180 * (-1) / pi)); – 진민수 Nov 08 '18 at 02:48
  • @paxdiablo else dq.push_back(90+atan2(x, y) * 180 * (-1) / pi); } else if (r == len) { if ((x > 0 && y <= 0) || (x >= 0 && y < 0)) dq.push_back(360 + (90 + atan2(x, y) * 180 * (-1) / pi)); else dq.push_back(90+atan2(x, y) * 180 * (-1) / pi); } } sort(dq.begin(), dq.end()); if (dq.size() >= 2) { for (int i = 0; i < dq.size() - 1; i++) { ans = max(ans, dq[i + 1] - dq[i]); } ans = max(ans, 360 - dq.back() + dq.front()); printf("%0.6f", ans); } else cout << "360.000000"; } – 진민수 Nov 08 '18 at 02:49
  • @paxdiablo I just changed the double to long double in this code and the print format from f to lf. At this time, long double received wa and dobule received ac. – 진민수 Nov 08 '18 at 02:52
  • @진민수: what is `wa` and `ac`? They appear *nowhere* in the code and you still haven't responded to the request by Kingsley for clarification. Additionally, I'm not certain how much use it is to provide a link to a page written in Korean, though that's a guess on my part based on Google Translate autodetect of your name :-) So apologies if that's wrong. In any case, I'll put your code into the question so others don't have to reformat it. – paxdiablo Nov 08 '18 at 03:10
  • What I *will* say is that, when using the test data on that page (I can read numbers, if not Korean), the code you posted gives the same result (90 and 180) as it seems to suggest, with or without the changes, though I used the correct `Lf` rather than `lf` specifier. With the latter, it appears to give me zero in both cases, so I'll add that to my answer as something to watch out for. – paxdiablo Nov 08 '18 at 03:25
  • @paxdiablo The problem was resolved after changing the output to Lf. Thank you – 진민수 Nov 08 '18 at 03:51
2

The implementation of long double changes on the compiler and the hardware.

Visual Studio just uses long double as a synonym for double. You will need to use the intel compiler on windows to make use of extended precision hardware on intel architectures, or GCC (versions > 4.3). Source: https://en.wikipedia.org/wiki/Long_double

If you want to update your question to include a code sample or details on your compiler & architecture, I can add possibly more detail to the answer. But generally (on Intel) long double uses 80-bit hardware floating point operations.

EDIT: I ran Paxdiablo's code on a Sun/Oracle SparcV9 solaris box:

              double        long double
           ============    =============
max        1.79769e+308      1.18973e+4932
min        2.22507e-308      3.3621e-4932
lowest    -1.79769e+308     -1.18973e+4932
digits10             15                 33
Kingsley
  • 14,398
  • 5
  • 31
  • 53
  • 1
    Formally, `long double` is not a synonym for `double`. It's required to be a distinct type. It can be the same size and have the same properties. – Pete Becker Nov 01 '18 at 15:42