Порядок выполнения операций и точность

      Комментарии к записи Порядок выполнения операций и точность отключены

Главная Форумы Программирование Программирование на С++ Порядок выполнения операций и точность

В этой теме 1 ответ, 2 участника, последнее обновление  Васильев Владимир Сергеевич 8 мес. назад.

  • Автор
    Сообщения
  • #2871

    questioner
    Участник

    Есть упорядоченный массив дробных чисел (или просто сходящаяся последовательность). Нужно вычислить сумму (например) элементов. На полученный результат почему-то оказывает влияние порядок обработки элементов. Кроме того, на результат влияет начальное значение.

    В качестве примера я взял сумму ряда 1/x при изменении x от 1 до 10000. Моя программа считает сумму при изменении индексов в одном направление, а потом в другом. Кроме того, считается сумма при начальном значении накопителя результата равным тысяче. Каждый способ дает свой результат, но между запусками программы эти результаты не отличаются, т.е. это не связано с мусором, расположенным в памяти изначально:

    #include <iostream> 
    #include <iomanip> 
     
    using namespace std;
     
    int main(void) { 
      double sum;
      const double one = 1;
      
      sum = 1000;
      for (long int i = 1; i < = 10000; ++i) {
        sum += one/i;
      }
      sum -= 1000;
      cout << "from 1 init 1000 sum : " << setprecision(15) << sum << endl;
      
      sum = 0;
      for (long int i = 1; i <= 10000; ++i) {
        sum += one/i;
      }
      cout << "from 1 init 0 sum : " << setprecision(15) << sum << endl;
      
      sum = 0;
      for (long int i = 10000; i >= 1; --i) {
        sum += one/i;
      }
      cout << "to 1 sum: " << setprecision(15) << sum << endl;
    } 

    Внутри циклов в любом случае выполняется одна и та же работа, но результат оказывается различным. Видимо, накапливается какая-то погрешность, но откуда она берется и в каком случае она будет наименьшей?

  • #2873

    Числа в компьютере хранятся в виде мантиссы (дробной части) и порядка (множителя). Образно, число 123.456 – это дробная часть .123456 и порядок равный трем: .123456 * 10^3.

    Перед выполнением любых операций над числами выполняется приведение чисел к одному порядку (порядку большего числа). Например:

    .12 * 10^1 + .345 * 10^2
    =
    .012 * 10^2 + .345 * 10^2

    Только после этого выполняется операция над мантиссами. Однако, подумайте, что произойдет, если сложить очень большое и очень маленькое число? – при приведении чисел к одному порядку мантисса меньшего числа будет дополнена большим количеством нулей, однако количество разрядов ограничено, поэтому произойдет потеря точности. Однако, при сложении двух (даже очень маленьких чисел) одного порядка – потери точности не будет.

    В связи с этим, самая низкая точность рассмотренном примере будет показана в случае, когда начальное значение суммы инициализировано большим числом (при прибавлении к нему 1./10000 результат скорее всего вообще не изменится.
    Более хорошие показатели точности будут у случая, когда начальное значение задается нулем, а самые лучшие – если сложение производить в порядке увеличения членов ряда (тогда операции будут происходить над числами примерно одного порядка).

Для ответа в этой теме необходимо авторизоваться.