Я хочу знать разницу между длинным двойным и двойным - PullRequest
0 голосов
/ 01 ноября 2018

Для любой алгоритмической проблемы допускается ошибка 10 -6 .

Я объявил long double как переменную в своем первом решении и получил WA.

Но когда я объявил переменную как double, я получил AC.

Я хочу знать, почему это решение было принято, потому что, как известно, long double точнее, чем double. Я ничего не менял, кроме переменных, методов вывода.

Вот мой код:

#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";
}

Единственные изменения, которые я сделал:

  • изменение double на long double; и
  • изменение спецификатора формата printf с f на lf.

Ответы [ 3 ]

0 голосов
/ 01 ноября 2018

... long double, как известно, точнее, чем double.

Нет, это действительно нет. Это может быть, но это ни в коем случае не гарантируется.

Различие между этими двумя типами подробно описано в стандарте (в данном случае, C++17 [basic.fundamental]/8, хотя более ранние итерации также имеют похожую формулировку). Стандарт говорит о типах с плавающей точкой (мой акцент):

Существует три типа с плавающей точкой: float, double и long double.

Тип double обеспечивает не менее такой же точности, как float, а тип long double обеспечивает не менее такой же точности, как double.

Набор значений типа float является подмножеством набора значений типа double; набор значений типа double является подмножеством набора значений типа long double.

Представление значений типов с плавающей запятой определяется реализацией.

Поскольку «подмножество» включает в себя возможность того, что два набора идентичны (аксиоматично, что A ⊂ A), нет фактического требования, чем long double имеет больший диапазон и / или точность, чем double хотя иногда это так.

Если вы хотите выяснить, в чем различия в вашей реализации, вы должны искать класс numeric_limits в заголовке <limits>, как показано в следующей демонстрационной программе:

#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';
}

Вывод на моей системе отформатирован для удобства чтения:

              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

Вы можете видеть, что мой диапазон значительно больше для long double, а также есть (примерно) дополнительные три десятичных знака точности.


С точки зрения того, как это может повлиять на ваш код, трудно сказать, поскольку вы на самом деле не предоставили адекватного описания того, в чем заключается проблема (в частности, что означают wa и ac). Однако, поскольку long double может иметь большую точность и / или диапазон, чем double, вполне возможно, что это может повлиять на поведение вашего кода.

Я должен также упомянуть, что правильный спецификатор формата для long double на самом деле %Lf (с заглавной буквы L), а не %lf. Это может вызвать у вас проблемы, поскольку с данными испытаний, приведенными на странице, на которую вы ссылаетесь в комментарии, я получаю правильный результат для double / %f и long double / %Lf.

Но он дает разные результаты (и, в этом отношении, gcc предупреждение) для long double / %lf.

0 голосов
/ 01 ноября 2018

Используя этот код, вы легко поймете, что long double должен быть в два раза точнее, чем double.

#include<iostream>
using namespace std;
main()
{
cout<<"size of double is "<<sizeof(double)<<" bytes"<<endl;
cout<<"size of long double is "<<sizeof(long double)<<" bytes";
return 0;
}
0 голосов
/ 01 ноября 2018

Реализация long double изменений на компиляторе и оборудовании.

Visual Studio просто использует long double как синоним double. Вам нужно будет использовать компилятор Intel для Windows, чтобы использовать аппаратное обеспечение повышенной точности на архитектурах Intel или GCC (версии> 4.3). Источник: https://en.wikipedia.org/wiki/Long_double

Если вы хотите обновить свой вопрос, включив в него пример кода или сведения о своем компиляторе и архитектуре, я могу добавить, возможно, более подробную информацию к ответу. Но обычно (на Intel) long double использует 80-битные аппаратные операции с плавающей запятой.

РЕДАКТИРОВАТЬ: Я запустил код Паксдиабло на солярисе Sun / Oracle SparcV9:

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