Как добавить два больших числа двойной точности в c ++ - PullRequest
3 голосов
/ 15 октября 2019

У меня есть следующий фрагмент кода

#include <iostream>
#include <iomanip>

int main()

{
    double  x = 7033753.49999141693115234375;
    double  y = 7033753.499991415999829769134521484375;
    double z = (x+ y)/2.0;

    std::cout  << "y is " << std::setprecision(40) << y << "\n";
    std::cout  << "x is " <<  std::setprecision(40) << x << "\n";
    std::cout  << "z is " << std::setprecision(40) << z << "\n";

    return 0;
}

Когда запускается приведенный выше код, я получаю,

y is 7033753.499991415999829769134521484375
x is 7033753.49999141693115234375
z is 7033753.49999141693115234375

Когда я делаю то же самое в Wolfram Alpha, значение z равносовершенно другой

 z = 7033753.4999914164654910564422607421875 #Wolfram answer

Я знаком с точностью с плавающей запятой и то, что большие числа вдали от нуля не могут быть точно представлены. Это то, что здесь происходит? В любом случае, в c ++ я могу получить тот же ответ, что и Вольфрам, без потери производительности?

Ответы [ 2 ]

6 голосов
/ 15 октября 2019

большие числа от нуля не могут быть точно представлены. Это то, что здесь происходит?

Да.

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

Есть ли в любом случае в C ++, где я могу получить такой же ответ, как Вольфрам ...

Выпотенциально может получить тот же ответ, используя long double. Моя система дает точно такой же результат, как и Вольфрам. Обратите внимание, что точность long double варьируется между системами даже среди систем, которые соответствуют стандарту IEEE 754.

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

... без штрафа за производительность?

Нет. Точность идет со стоимостью.

0 голосов
/ 15 октября 2019

То, что IOStreams печатает с точностью до 40 значащих десятичных знаков точности, не означает, что значение, которое вы выводите на самом деле , имеет такой большой точности.

Типичный doubleпринимает до 17 значащих десятичных знаков (ish);кроме того, то, что вы видите, совершенно произвольно.

С точки зрения ответа eerorika, похоже, что ответ Wolfram Alpha также нарушает это, хотя, возможно, с некоторым пределом точности, чем ваш.

Вы можете попробовать другой подход, такой как библиотека "bignum", или ограничить себя точностью, обеспечиваемой выбранными вами типами.

...