我想知道长双倍和双倍之间的区别

I want to know the difference between a long double and a double

本文关键字:区别 之间 想知道      更新时间:2023-10-16

对于任何算法问题,允许错误为10-6

我在第一个解决方案中将long double声明为变量并得到了 WA。

但是,当我将一个变量声明为double时,我得到了一个 AC。

我想知道为什么做出这个决定,因为众所周知long doubledouble更准确。除了变量、输出方法之外,我没有更改任何东西。

这是我的代码:

#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

...众所周知,长双精度比双精度更准确。

不,真的不是。可能是,但绝不是保证的

两种类型之间的区别在标准中有详细说明(在这种情况下,C++17 [basic.fundamental]/8,尽管早期的迭代也有类似的措辞)。该标准对浮点类型有这样的说法(我的强调):

有三种浮点类型:floatdoublelong double

double型提供的精度至少float一样多,而long double型提供的精度至少double一样多。

float类型的值集是double类型的值集的子集;double类型的值集是long double类型的值集的子集。

浮点类型的值表示形式是实现定义的。

由于"子集"包括两个集合相同的可能性(公理是公理的A ⊂ A),因此没有实际要求比long double具有double更大的范围和/或精度,尽管有时确实如此。

如果您想弄清楚实现中的区别是什么,您应该按照以下演示程序查看<limits>标头中的numeric_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来说要大得多,而且(大约)还有额外的三个十进制数字的精度。


至于这会对你的代码产生什么影响,很难说,因为你实际上没有提供对问题是什么的充分描述(特别是waac的意思)。但是,由于long double可能比double具有更高的精度和/或范围,因此可以想象这可能会影响代码的行为方式。

我还应该提到,long double的正确格式说明符实际上是%Lf(大写L)而不是%lf。这很可能会给您带来问题,因为根据您在评论中链接到的页面上给出的测试数据,我得到了double/%flong double/%Lf的正确结果。

但它为long double/%lf提供了不同的结果(以及gcc警告)。

编译器和硬件上long double更改的实现。

Visual Studio只是使用long double作为double的同义词。 您需要在 Windows 上使用英特尔编译器,才能在英特尔架构或 GCC(4.3>版本)上使用扩展精度硬件。 来源: https://en.wikipedia.org/wiki/Long_double

如果你想更新你的问题,包括一个代码示例或关于你的编译器和架构的详细信息,我可以在答案中添加更多细节。 但通常(在英特尔上)长双精度使用 80 位硬件浮点运算。

编辑:我在Sun/Oracle SparcV9 solaris盒子上运行Paxdiablo的代码:

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