Подтвердить что ты не робот

Избежать ошибки округления (плавно) С++

http://www.learncpp.com/cpp-tutorial/25-floating-point-numbers/ В последнее время я обсуждал С++.

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

Может кто-нибудь, пожалуйста, помогите мне в том, как избежать ошибки округления?

В учебнике показан пример кода

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

Выводит

+0,10000000000000001

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

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

Спасибо.

4b9b3361

Ответ 2

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

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

Ответ 3

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

Ответ 4

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

#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

}

Ответ 5

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

 #include <iostream>
 #include <iomanip>
    int main() {
          using namespace std;
          #include <iomanip>


    double dValue = 0.19213;
    cout << fixed << setprecision(2) << dValue << endl


       }

выводится как:

dValue = 0.19

Ответ 6

Когда вы вычисляете простую вещь как дисперсию, у вас может быть такая проблема... вот мое решение...

int getValue(double val, int precision){
std::stringstream ss;
ss << val;
string strVal = ss.str();
size_t start = strVal.find(".");

std::string major = strVal.substr(0, start);
std::string minor = strVal.substr(start + 1);

// Fill whit zero...
while(minor.length() < precision){
    minor += "0";
}

// Trim over precision...
if(minor.length() > precision){
  minor = minor.substr(0, precision);
}

strVal = major + minor;
int intVal = atoi(strVal.c_str());

return intVal;
}

Итак, вы сделаете свой расчет в целочисленном диапазоне... например, 2523.49 стал 252349 с точностью цифр буксировки и 2523490 с точностью древовидной цифры... если вы вычисляете среднее значение, например, сначала вы конвертируете все значение в целое число, суммируете и возвращаете результат в double, поэтому вы не накапливаете ошибку... Ошибка - это усиление работы, такое как квадратный корень и функция мощности...