Как работать с большими суммами чисел с плавающей запятой (C ++) - PullRequest
0 голосов
/ 18 июня 2020

Я пытаюсь понять, почему вычисление определителя матрицы 3x3 таким образом дает неверные результаты:

#include <iostream>
#include <array>
#include <vector>

int main(int argc, char const *argv[])
{
    const int dim = 3;
    std::vector<std::vector<float>> data;
    data.resize(dim, std::vector<float>(dim, 0));
    std::array<float, dim*dim> myArray = {
        -1000.0, -1000.0, -1000.0, 
        -1000.0, -1000.0, -1000.0, 
        -1000.0, -1000.0, -999.0
    };

    for(int i = 0; i < dim; i++){
        for(int j = 0; j < dim; j++){
            data[i][j] = myArray[dim*i + j];
        }
    }
    float det = 
    data[0][0] * data[1][1] * data[2][2] + 
    data[0][1] * data[1][2] * data[2][0] + 
    data[0][2] * data[2][1] * data[1][0] - 
    data[2][0] * data[1][1] * data[0][2] - 
    data[0][0] * data[1][2] * data[2][1] - 
    data[1][0] * data[0][1] * data[2][2];

    float anotherDet = 0;
    for(int i = 0; i < 2; i++){
        anotherDet = anotherDet + 1000 * 1000 * 1000;
    }
    for(int i = 0; i < 2; i++){
        anotherDet = anotherDet - 1000 * 1000 * 1000;
    }
    anotherDet = anotherDet - 1000 * 1000 * 999;
    anotherDet = anotherDet + 1000 * 1000 * 999;

    std::cout << det << " " << anotherDet << std::endl;
    return 0;
}

Результатом этого кода является -64 0, тогда как действительный определитель такой матрицы должен быть нулевым. Я подозреваю, что ошибка связана с точностью с плавающей запятой, но я до сих пор не могу понять, почему возникают такие несоответствия.

Я попробовал отладить и действительно обнаружил, что существует продолжающаяся ошибка округления. -2999000060 - это значение det в середине этой большой суммы.

Но если я попробую следующее:

float det2 = 
    1000 * 1000 * 1000 + 
    1000 * 1000 * 1000 + 
    1000 * 1000 * 999 - 
    1000 * 1000 * 1000 - 
    1000 * 1000 * 1000 - 
    1000 * 1000 * 999;

Это даст правильное значение 0, но только потому что это операция arithmeti c, и поэтому ошибок округления нет.

Edit: теперь я понимаю, как операции с такими большими числами могут нести некоторую ошибку округления.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...