如何准确地划分两个双打

时间:2009-10-08 00:39:45

标签: c++ math floating-point double

我有两个

double a, b;

我知道以下是真的

-1 <= a/b <= 1

然而b可以任意小。当我天真地这样做并只计算值

 a/b

上面指定的条件在某些情况下不成立,我得到的值绝对值大于1(如13或14)。

如何确保当我除以b时,我得到一个值,以便可以强制执行上述条件。在我无法保证这一点的情况下,我很乐意将计算值a / b设置为0.

7 个答案:

答案 0 :(得分:10)

你需要强制执行的是abs(a)≤abs(b)。如果该条件成立,则-1≤a/b≤1,无论使用何种浮点精度。您的逻辑错误发生在除法之前,因为在分割点abs(a)> abs(b)违反了您的先验要求。

答案 1 :(得分:10)

IEEE-754系统上的划分是正确舍入操作,这意味着如果没有发生上溢或下溢,结果将始终在数学“无限精确”的0.5“ulp”范围内结果。在非FP-nerd中,这意味着结果总是在确切答案的约2 ^ -53的范围内。既然你知道无限精确的结果在-1和1之间,就不会发生溢出;下溢可以,但这会导致数字非常非常接近于零,而不是13阶。

您的条件实际上并不成立,或者您所在的系统没有IEEE-754算术,或者您的代码中存在错误。你能发布产生这个结果的a和b的值,以及你用来进行除法并打印结果的代码吗?

答案 2 :(得分:1)

由于下溢,您实际上不太可能触发数据丢失。虽然有可能双打有一个令人难以置信的范围,你不太可能击中它。

我认为问题出在此之前的某个地方。你有一个逻辑错误,或者你只是通过一堆操作吃掉了可用的精度。特别警惕添加和减少。 1E20 + 1 = 1E20。

如果是因为吃掉了精确度,那么你将不得不重新设计你的程序或者使用任意精度的库来计算数学。 (请注意 - SLOW

答案 3 :(得分:0)

我对你的问题感到有点困惑,但如果你建议-1&lt; = a / b&lt; = 1对所有实际值a和b都适用,那绝对不是这样的。考虑:

1 / 0.5 = 2

如果你想检查除法是否在[-1,1]之内,为什么不进行除法,然后当它落在介于-1和1之间时你可以采取行动。

答案 4 :(得分:0)

如果你真的想测试你的理论,这是一个精确的问题(虽然其他答案使你看起来不可能得到你得到的结果),你应该使用GMP。你已经说过你要“除以一个太小,小于机器精度的数字。” GMP的C ++绑定具有所有内容的算术运算符,与C绑定give them a try相比,实际上使用起来很愉快!

      mpf_class f(1.5);        // default precision
      mpf_class f(1.5, 500);   // 500 bits of precision (at least)
      double out = f.get_d();  // get a double out of an mpf_class

答案 5 :(得分:0)

我能想到的唯一情况是,如果a/b 介于-1和1之间,但不是,因为ab来源于使它们对浮点错误非常敏感的计算。

例如,如果您尝试以弧度计算b = 2-2*cos(theta)a = theta*theta为弧度,接近零,则会遇到问题,因为b的计算涉及到数字的减法接近1,尽管数学上小角度的答案非常接近1.0。 (如果我使用Spidermonkey Javascript引擎运行theta = 0.4e-7的a / b计算,即使它真的应该接近1.0,我也会得到1.029)

280Z28的答案就是你想要的地方,但是如果不了解a和b是如何得出的,并且在什么条件下会得到不良结果,很难说最好的方法是确保计算给出有意义的数字。

答案 6 :(得分:0)

在达到这一点之前,你肯定有一些问题。无论如何,如果你准备接受0结果,你可以在这里消除这个问题。

float Calculate(float a, float b)
{
    if (abs(a) > abs(b))
    {
        return 0;
    }
    else
    {
        return a/b;
    }
}