избегайте погрешности округления (плавающий конкретно) C++

http://www.learncpp.com/cpp-tutorial/25-floating-point-numbers/ я был об этом в последнее время для рассмотрения C++.

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

Кто-то может помочь мне с тем, как избежать погрешности округления?

Учебное руководство показывает пример кода

#include 
int main()
{
    using namespace std;
    cout << setprecision(17);
    double dValue = 0.1;
    cout << dValue << endl;
}

Это производит

0.10000000000000001

Плаванием по умолчанию сохранен 6 цифрами точности. Поэтому, когда мы переопределяем значение по умолчанию, и просит больше (n этот случай, 17!!), мы можем встретиться с усечением (как объяснено учебным руководством также). Для двойного самое высокое равняется 16.

В целом, как хорошие программисты на C++ избегают погрешности округления? Вы парни всегда смотрят на двоичное представление числа?

Спасибо.

10
задан CppLearner 5 August 2010 в 23:41
поделиться

4 ответа

Канонический совет по этой теме - прочитать «Что должен знать каждый компьютерный ученый об арифметике с плавающей запятой» Дэвида Голдберга.

15
ответ дан 3 December 2019 в 22:34
поделиться

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

0
ответ дан 3 December 2019 в 22:34
поделиться

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

#include <iostream>
#include <iomanip>

int main() {

  using namespace std;

  cout << setprecision(17);

  double v1=1, v1D=10; 
  cout << v1/v1D << endl;  // 0.10000000000000001


  double v2=3, v2D=1000;  //0.0030000000000000001
  cout << v2/v2D << endl;

  // v1/v1D + v2/v2D = (v1*v2D+v2*v1D)/(v1D*v2D)

  cout << (v1*v2D+v2*v1D)/(v1D*v2D) << endl; // 0.10299999999999999

}
0
ответ дан 3 December 2019 в 22:34
поделиться

Большинство подпрограмм вывода с плавающей запятой проверяют, очень ли близок ответ к тому, чтобы быть представленным в базе 10, и округляют ответ, чтобы фактически быть четным при выводе. Устанавливая точность таким образом, вы замыкаете этот процесс.

Это округление сделано потому, что почти ни один ответ, который выходит даже в базе 10, не будет четным (т.е. оканчивается бесконечной цепочкой завершающих нулей) в базе 2, которая является базой, в которой число представлено внутри. Но, конечно, общая цель процедуры вывода состоит в том, чтобы представить числа в удобной для человека форме, и большинство людей в мире сегодня читают числа с основанием 10.

0
ответ дан 3 December 2019 в 22:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: