двойная перегрузка 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 (единиц наименьшей точности), а возможно, и больше в плохих реализациях.

Другие вопросы по тегам