避免舍入误差(特别是浮动)C++

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3420009/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 12:48:05  来源:igfitidea点击:

avoid rounding error (floating specifically) c++

c++

提问by CppLearner

http://www.learncpp.com/cpp-tutorial/25-floating-point-numbers/I have been about this lately to review C++.

http://www.learncpp.com/cpp-tutorial/25-floating-point-numbers/我最近一直在讨论这个来回顾 C++。

In general computing class professors tend not to cover these small things, although we knew what rounding errors meant.

虽然我们知道舍入误差意味着什么,但一般而言,计算机课程教授往往不会涵盖这些小事情。

Can someone please help me with how to avoid rounding error?

有人可以帮我解决如何避免舍入错误吗?

The tutorial shows a sample code

本教程展示了一个示例代码

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

This outputs

这输出

0.10000000000000001

0.10000000000000001

By default float is kept 6-digits of precisions. Therefore, when we override the default, and asks for more (n this case, 17!!), we may encounter truncation (as explained by the tutorial as well). For double, the highest is 16.

默认情况下,float 保持 6 位精度。因此,当我们覆盖默认值并要求更多时(在本例中为 17 !!),我们可能会遇到截断(如教程中所述)。对于双人,最高为 16。

In general, how do good C++ programmers avoid rounding error? Do you guys always look at the binary representation of the number?

一般而言,优秀的 C++ 程序员如何避免舍入错误?你们总是看数字的二进制表示吗?

Thank you.

谢谢你。

回答by Jim Lewis

The canonical advice for this topic is to read "What Every Computer Scientist Should Know About Floating-Point Arithmetic", by David Goldberg.

这个主题的规范建议是阅读David Goldberg 所著的“What Every Computer Scientist should Know About Floating-Point Arithmetic”

回答by Omnifarious

Most floating point output routines look to see if the answer is very close to being even when represented in base 10 and round the answer to actually be even on output. By setting the precision in this way you are short-circuiting this process.

大多数浮点输出例程会查看答案是否非常接近以基数 10 表示的偶数,并将答案四舍五入以实际输出偶数。通过以这种方式设置精度,您可以缩短此过程。

This rounding is done because almost no answer that comes out even in base 10 will be even (i.e. end in an infinite string of trailing 0s) in base 2, which is the base in which the number is represented internally. But, of course, the general goal of an output routine is to present the number in a fashion useful for a human being, and most human beings in the world today read numbers in base 10.

之所以进行四舍五入,是因为即使以 10 为底的结果几乎都不会在以 2 为基数(即内部表示数字的基数)中为偶数(即以无限的尾随 0 字符串结尾)。但是,当然,输出例程的总体目标是以对人类有用的方式呈现数字,而当今世界上的大多数人都以 10 为基数读取数字。

回答by Timo Geusch

Short version - you can't really avoid rounding and other representation errors when you're trying to represent base 10 numbers in base 2 (ie, using a float or a double to represent a decimal number). You pretty much either have to work out how many significant digits you actually have or you have to switch to a (slower) arbitrary precision library.

简短版本 - 当您尝试以基数 2 表示基数为 10 的数字(即,使用浮点数或双精度数来表示十进制数)时,您无法真正避免舍入和其他表示错误。您几乎要么必须计算出您实际拥有多少有效数字,要么必须切换到(较慢的)任意精度库。

回答by Shelwien

In other words, to minimize rounding errors, it can be helpful to keep numbers in decimal fixed-point (and actually work with integers).

换句话说,为了最大限度地减少舍入误差,将数字保持在十进制定点(并且实际上使用整数)可能会有所帮助。

#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

}

回答by castaway2000

You want to use the manipulator called "Fixed" to format your digits correctly so they do not round or show in a scientific notation after you use fixed you will also be able to use set the precision() function to set the value placement to the right of the . decimal point. the example would be as follows using your original code.

您想使用名为“Fixed”的操纵器正确格式化您的数字,以便在您使用 fixed 后它们不会舍入或以科学记数法显示,您还可以使用 set precision() 函数将值放置设置为的权利。小数点。该示例将如下使用您的原始代码。

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


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


       }

outputs as:

输出为:

dValue = 0.19

回答by user3215378

When you calculate simple thing like variance you can have this kind of problem... here is my solution...

当你计算像方差这样的简单东西时,你可能会遇到这种问题......这是我的解决方案......

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;
}

So you will make your calcul in the integer range... for example 2523.49 became 252349 whit a precision of tow digits, and 2523490 whit a precision of tree digit... if you calculate the mean for example first you convert all value in integer, make the summation and get the result back in double, so you not accumulate error... Error are amplifie whit operation like square root and power function...

因此,您将在整数范围内进行计算……例如,2523.49 变为 252349,具有两个数字的精度,而 2523490 具有树数字的精度……如果您首先计算平均值,则首先将所有值转换为整数,求和并得到双倍的结果,这样你就不会累积误差......误差是像平方根和幂函数这样的放大运算......