二进制搜索以查找未知数字

时间:2015-03-05 21:23:10

标签: c# math

我有一个名为Slice的函数。它消耗2个值。第一个节点值和第二个节点值。我试图找到[First,Second]之间的值,使函数G(x)变为零或非常接近,最接近2位小数。我可以使用从第一个数字开始并递增.01的迭代函数来解决这个问题,但这可能需要很长时间。

我正在尝试使用二进制运行时。棘手的部分是我发现中点后我不知道要采取哪个切片。如果我能得到一些提示或建议继续请。

public double Slice(decimal first, decimal last)
{
    double firstNodeValue         = FinalOptionDecider(first);        

    double midNodeValue           = FinalOptionDecider((last + first) / 2);

    double lastNodeValue          = FinalOptionDecider(last);   
}

4 个答案:

答案 0 :(得分:1)

二进制搜索依赖于已排序的数据来决定下一个搜索的一半。因此,除非您想要传递数据的函数也按排序顺序保留数据,否则不能使用二进制搜索。

您有两种选择:

  • 放弃二元搜索,只进行线性搜索
  • 处理所有输入,排序和二进制搜索输出(您可以在字典中将输入和输出配对以检索输入)。

答案 1 :(得分:1)

作为任意函数的一般问题,这可能很难解决。如果你能做出某些假设,那就容易多了。您开始使用的算法称为二分算法。

首先,您需要包含您要查找的值。因此,如果您希望FinalOptionDecider(x)返回零,则firstNodeValuelastNodeValue必须为正数和负数。如果它们既是正面的,也可能都是负数,那么您无法将所需的值括起来,也无法保证在firstlast之间进行搜索会找到答案。而且您也无法保证您可以做出下一段中描述的决定。所以先检查一下。

这个条件基本上就是你的答案......当你得到midNodeValue时,你需要检查一下,看看你想要的值是否在firstNodeValuemidNodeValue之间,或者是否在{{1}之间1}}和midNodeValue。根据它的不同,您需要再次对该间隔进行切片。重复,直到达到所需的精度。

如果你的函数有多个零(比如g(x)= x ^ 2 - 1那么),那么你只能找到一个零。

答案 2 :(得分:1)

二进制搜索是关于缩小间隔,直到间隔仅由一个值组成。我不知道你的意思是随机的,但二进制排序只能在排序的数据集上执行。 请记住,随机搜索几乎总是比排序然后搜索更快!

答案 3 :(得分:1)

您只是在寻找root-finding algorithm。您在此处开始实施的只是Bisection method。二分并不是最快的,但它的主要优点是它很简单并且保证在指定的时间间隔内收敛到 a 根,只要函数在区间内改变符号并且函数是连续的(因此,通过intermediate value theorem,一个根保证存在于区间中。这是一个简单的,有点通用的二分法方法实现:

public static decimal FindRoot( decimal first, decimal last, Func<decimal, double> f, double value, decimal tolerance = 0.01m )
{
    double fa = f( first );
    double fb = f( last );

    if( fa * fb > 0 )
    {
        throw new ArgumentException( "Interval not guaranteed to contain root." );
    }
    else if( fa == 0 )
    {
        return first;
    }
    else if( fb == 0 )
    {
        return last;
    }

    while( Math.Abs( first - last ) > tolerance )
    {
        decimal mid = ( first + last ) / 2;
        double fc = f( mid );
        if( fc * fb < 0 )
        {
            first = mid;
            fa = fc;
        }
        else if( fc * fa < 0 )
        {
            last = mid;
            fb = fc;
        }
        else
        {
            return mid;
        }
    }

    return ( first - last ) * (decimal) ( fa / ( fb - fa ) ) + first;
}