补偿双重/浮动不准确

时间:2016-08-17 07:36:09

标签: c++ comparison precision

我写了一个数学计算器,它从用户那里接收一个字符串并解析它。它使用双精度来保存计算时涉及的所有值。解决之后,我会打印它,并使用std::setprecision()确保输出正确(例如0.9999999将在打印输出时变为1

返回将输出的字符串:

//return true or false if this is in the returnstring.

if (returnString.compare("True") == 0 || returnString.compare("False") == 0) return returnString;

    //create stringstream and put the answer into the returnString.
    std::stringstream stream;
    returnString = std::to_string(temp_answer.answer);

    //write into the stream with precision set correctly.
    stream << std::fixed << std::setprecision(5) << temp_answer.answer;


    return stream.str();

我知道使用双打和浮动时的准确性问题。今天我开始研究代码,以便用户可以比较两个数学字符串。例如,1=1将评估为true,2>3 false等等。这是通过为比较运算符的每一侧运行我的数学表达式解析器,然后比较答案。

我现在面临的问题是当用户输入1/3*3=1之类的内容时。当然因为我使用双打,解析器将返回0.999999作为答案。通常在解决非比较问题时,如前所述,在使用std::setprecision()的打印时间进行补偿。但是,当比较两个双打时,它将返回false作为0.99999!=1。我如何在比较双精度时得到它,这种不准确性得到补偿,答案是否正确返回?这是我用来比较数字本身的代码。

bool math_comparisons::equal_to(std::string lhs, std::string rhs)
{
    auto lhs_ret = std::async(process_question, lhs);
    auto rhs_ret = std::async(process_question, rhs);
    bool ReturnVal = false;

    if (lhs_ret.get().answer == rhs_ret.get().answer)
    {
        ReturnVal = true;
    }

    return ReturnVal;
}

我认为需要进行某种舍入,但我不能100%确定如何正确完成它。如果已经解决了,请原谅我 - 我找不到搜索的内容。谢谢!

2 个答案:

答案 0 :(得分:2)

假设answerdouble,请替换此

lhs_ret.get().answer == rhs_ret.get().answer

abs(lhs_ret.get().answer - rhs_ret.get().answer) < TOL

其中TOL是适当的容差值。

不应将浮点数与==进行比较,而应检查绝对差值是否小于给定的容差。

需要提到一个难点:双精度的精确度约为16位小数。所以你可以设置TOL=1.0e-16。这仅在您的数字小于1时才有效。对于16位数字,这意味着公差必须大到1。

因此,您可以假设您的数字小于10e8,并使用相对较大的容差,例如10e-8,或者您需要做一些更复杂的事情。

答案 1 :(得分:1)

首先考虑:

作为一个基本的经验法则,double将是一个大约16dp的值,其中dp是小数位,或1.0e-16。你需要知道这只适用于小于一(1)IE的数字10.你必须围绕这个事实操作你只能有15dp EG:10.0e-15等等...由于计算机在基数2中计数,而人数在基数10中计算,某些值永远无法在&#34;大多数&#34; 现代操作系统使用的位范围内正确表达。

这可以通过以二进制或基数2表示0.1无限长的事实来突出显示。

因此,您不应该通过==运算符比较有理数。相反,&#34;去&#34;常规使用的解决方案是:

您实施&#34;足够接近&#34; 解决方案。 IE:您将epsilon定义为一个值,例如:epsilon = 0.000001,并说明(value a - value b) < epsilon == true。我们所说的是if a - b is within e,对于我们计划的所有意图和目的,它足够接近被视为真实。

现在为epsilon选择一个值,这一切都取决于您需要的准确度。例如,与2D侧滚动平台游戏相比,可以假设您需要高水平的结构工程精度。

在您的情况下,您要替换代码的第7行的解决方案:

(lhs_ret.get().answer == rhs_ret.get().answer)

abs(lhs_ret.get().answer - rhs_ret.get().answer) < epsilon其中abs是绝对值。 IE忽略值lhs的符号。

有关更多背景信息,我强烈推荐这个关于麻省理工学院开放课件的讲座,该课程以易于理解的方式解释。

http://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-00sc-introduction-to-computer-science-and-programming-spring-2011/unit-1/lecture-7-debugging/

相关问题