Почему добавление большого к малому в плавающей точке вносит больше ошибок? - PullRequest
0 голосов
/ 04 ноября 2018

Не знаю, почему, но если я добавлю большие к маленьким числам fp, похоже, что ошибка приращения будет больше :

#include <iostream>
#include <math.h>

int main() {
    std::cout.precision(50);

    const int numLoops = 1000;
    const long length = 10000;
    const double rate = 0.1;

    long totalLength = length * numLoops;
    long long steps = (long long)(totalLength / rate);

    double sum = 0.0;
    double sumRemainder = 0.0;
    for (long long step = 0; step < steps; step++) {
        if (sumRemainder >= length) {
            sumRemainder = fmod(sumRemainder, length);
        }

        sum += rate;
        sumRemainder += rate;
    }

    std::cout << "                  length: " << length << std::endl;
    std::cout << "               num loops: " << numLoops << std::endl;
    std::cout << "                    rate: " << rate << std::endl;
    std::cout << "                   steps: " << steps << std::endl << std::endl;
    std::cout << "                     sum: " << sum << std::endl;
    std::cout << "           sum remainder: " << sumRemainder << std::endl;
    std::cout << "                   error: " << abs(totalLength - sum) << std::endl;
    std::cout << "         error remainder: " << abs(length - sumRemainder) << std::endl;
    std::cout << std::endl;
}

Единственное различие между двумя суммами состоит в том, что одна для всех шагов, в то время как для другой я просто fmod результат, как только достигнут предел (таким образом, он ограничивается небольшим значением):

sumRemainder = fmod(sumRemainder, length);

Кажется, что это причина низкой ошибки при суммировании той же суммы: 1.884836819954216480255126953125e-05 против 0.01887054927647113800048828125

Может кто-нибудь объяснить мне, почему это происходит с умным примером?

1 Ответ

0 голосов
/ 05 ноября 2018

Для обработки больших или малых чисел формат с плавающей запятой масштабирует числа. Фиксированное число цифр используется для значимого и числа, и они масштабируются некоторой базой (часто 2), возведенной в степень, называемую показателем . Существует также знак , + или -, хотя этот знак иногда включается в значение и *. 1007 *

Например, при использовании двоичного формата значение 1.011 2 представляет 1 + 3/16 при масштабировании с показателем нуля (1.011 2 • 2 0 = 1 + 3/16), 11 при масштабировании с показателем 4 (1,011 2 • 2 4 = 11) и 11/32 при масштабировании с показателем -1 (1,011 2 • 2 -1 = 11/32).

Существует фиксированное количество цифр для значимых символов. Таким образом, только определенные числа могут быть представлены. Когда выполняется любая арифметика, точный математический результат округляется до ближайшего представимого числа. (Общее правило по умолчанию для округления - округление до ближайшего представимого значения и, в случае связей, округление, чтобы младшая цифра была четной.)

Например, в десятичном формате, который имеет три десятичных знака в своем значении, рассмотрите возможность добавления чисел 567 (5,67 • 10 2 ) и 789 (7,89 • 10 2 ) , Результат - 1356, но в нем слишком много цифр. Таким образом, оно округляется до 1360 (1,36 • 10 3 ). Ошибка округления 4.

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

Таким образом, при работе с большими числами ошибки округления больше.

...