двойная перегрузка 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
1 ответ
дважды перегруженные sin () и cos () не поддерживают 15-значную десятичную точность
Ни один числовой формат фиксированного размера не может «поддерживать» определенную точность, независимо от того, является ли это число с плавающей точкой, целым числом, фиксированной точкой или чем-то еще.
Всякий раз, когда результат операции, выполненной с использованием математики с действительными числами, не может быть представлен в числовом формате, может быть возвращено только приближение результата действительного числа. Результат в виде действительного числа должен быть округлен до некоторого представимого значения. Это приводит к ошибке округления.
Когда выполняется несколько операций, ошибки округления могут накапливаться и складываться по-разному. Взаимодействия и последствия могут быть очень сложными, и для этого есть целая область исследования - численный анализ .
В качестве простого примера рассмотрим целочисленную арифметику, в которой разрешение равно 1. Тем не менее, если мы вычислим 17/3•5 с
17/3*5
, мы получаем 25, где результат действительного числа будет 28⅓, а целочисленный результат, ближайший к идеальному результату, будет 28. Таким образом, вычисленный результат отличается на три единицы от наилучшего представимого результата (и на 3⅓ от результата действительного числа ) хотя мы сделали всего две операции. Целочисленная арифметика не может «поддерживать» 1 единицу точности.
В вашем примере ошибки округления возникают в следующих операциях:
- 9.80665 конвертируется в формат.
- Число π преобразуется в
double
формат. -
a1
а такжеa2
умножаются наpi
. - Эти продукты делятся на 180.
- Берутся синусы и косинусы этих частных.
-
2 * vy1
а также2 * vy2
делятся наg
. (Умножение на 2 не приводит к ошибке округления, так как его результат точно представлен в двоичной системе с плавающей запятой.) - Эти коэффициенты умножаются на
vx1
а такжеvx2
. - Эти продукты преобразуются в десятичную форму для отображения.
Кроме того,
sin
а также
cos
их сложно реализовать, и обычные реализации предпочитают скорость и предоставляют ее за счет допуска небольшой дополнительной ошибки. Их результаты могут отличаться на несколько единиц ULP (единиц наименьшей точности), а возможно, и больше в плохих реализациях.