双重载 sin() 和 cos() 不保持 15 位十进制精度



使用此链接作为指南,https://www.geeksforgeeks.org/difference-float-double-c-cpp/#:~:text=double%20is%20a%2064%20bit,15%20decimal%20digits%20of%20precision。double是一个64位IEEE 754双精度浮点数(1位为符号,11位为指数,52位为值),即double具有15个十进制数字的精度,下面的代码不保持15个十进制数字的精度。相反,14。

它适用于简单的弹丸运动计算器,其中,以 30 度发射的弹丸的范围应与以 60 度发射的相同弹丸的范围相匹配。

#include <iostream>
#include <iomanip>
int main()
{
const double g = 9.80665;
const double pi = 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679;
double a1 = 30.0;
double a2 = 60.0;
double v = 25.0;
double vx1 = v * cos(a1 * pi/180.0);
double vy1 = v * sin(a1 * pi/180.0);
double vx2 = v * cos(a2 * pi/180.0);
double vy2 = v * sin(a2 * pi/180.0);
double t_max1 = 2 * vy1 / g;
double t_max2 = 2 * vy2 / g;
double range1 = t_max1 * vx1;
double range2 = t_max2 * vx2;

std::cout << std::setprecision(16) << range1 << ", " << range2 << std::endl;
return 0;
}

输出:55.19375906810931, 55.19375906810933

双重载 sin() 和 cos() 不保持 15 位十进制精度

任何固定大小的数字格式都不可能"保持"特定的精度,无论它是浮点、整数、定点还是其他东西。

当使用实数数学执行的操作的结果不能以数字格式表示时,只能返回实数结果的近似值。实数结果必须四舍五入到某个可表示的值。这引入了舍入误差。

当有多个操作时,舍入误差可能会以各种方式累积和复合。相互作用和后果可能非常复杂,并且有一个完整的研究领域,数值分析,为它。

作为一个简单的示例,请考虑整数算术,其中分辨率为 1。然而,如果我们用17/3*5计算 17/3•5,我们得到 25,其中实数结果为 281/3,最接近理想结果的整数结果为 28。因此,即使我们只做了两个操作,计算结果也与最佳可表示结果相差三个单位(与实数结果相差 31/3)。整数算术不能"保持"1 个精度单位。

在您的示例中,舍入误差发生在以下操作中:

  • 9.80665 转换为double格式。
  • π的数字将转换为double格式。
  • a1a2分别乘以pi
  • 这些产品除以 180。
  • 取这些商的正弦和余弦。
  • 2 * vy12 * vy2g划分。(乘以 2 不会引入任何舍入误差,因为它的结果在基于二进制的浮点数中完全可以表示。
  • 这些商乘以vx1vx2.
  • 这些产品将转换为十进制进行显示。

此外,sincos很难实现,常见的实现更喜欢速度,并以允许一点额外的错误为代价来提供速度。他们的结果可能会偏离几个ULP(最不精确的单位),在糟糕的实现中可能会更多。

最新更新