加快C ++中双打的比较

时间:2015-06-08 20:09:05

标签: c++ arrays visual-studio-2012 double binary-search

我有一个函数,它使用二进制搜索在排序的双精度数组中查找索引,以便"搜索值"如果按升序排序,则大于或等于该索引处数组中的值,但严格小于后续索引处数组中的值。输入数组可以按升序或降序排序。

我在Microsoft Visual Studio 2012上分析了我的代码,该代码显示12%的时间用于此功能,而8%的时间用于比较"搜索值"和数组中的值。我想探讨加快这个功能的可能性。

/**
    Binary Search algorithm for a sorted array of doubles
    _sortedArr could be sorted ascending or descending
    Find the index in the array _sortedArr such that:
    _sortedArr[lowerIndex] <= _valToFind < _sortedArr[lowerIndex+1]
*/
size_t findInArray(const double _sortedArr[], size_t _len, double _valToFind)
{
    size_t startIndex = 0;

    if( _len <= 1 ) return startIndex;

    // Determine if the array is sorted ascending or descending
    unsigned int isAscending = (_sortedArr[_len-1] > _sortedArr[startIndex]);

    // To avoid looping through the array, detect edge cases first
    if( isAscending ) {
        if( _valToFind <  _sortedArr[startIndex+1] ) return startIndex;
        if( _valToFind >= _sortedArr[_len-1] ) return _len-1;
    } else {
        if( _valToFind >  _sortedArr[startIndex+1] ) return startIndex;
        if( _valToFind <= _sortedArr[_len-1] ) return _len-1;
    }

    size_t lowerIndex = startIndex + 1;
    size_t upperIndex = _len - 1; 
    size_t midIndex = 0;

    // Binary search loop
    while (upperIndex - lowerIndex > 1)
    {
        midIndex = (upperIndex + lowerIndex) >> 1; // (upperIndex+lowerIndex)/2

        // 8% of time spent executing the if-clause
        if (_valToFind >=  _sortedArr[midIndex] == isAscending)
            lowerIndex = midIndex;
        else
            upperIndex = midIndex;
    }

    return lowerIndex;
}

以下是测试此功能的方法:

int main (int argc, char *argv[])
{
    const double arr[] = {-3.0000000000000000, -2.5714285714285716, -2.1428571428571432,
                      -1.7142857142857146, -1.2857142857142860, -0.85714285714285743,
                      -0.42857142857142888, -3.3306690738754696e-016, 0.42857142857142821,
                      0.85714285714285676, 1.2857142857142854, 1.7142857142857140,
                      2.1428571428571423, 2.5714285714285707, 2.9999999999999991};

    size_t index = findInArray(arr, 15, 0.0);
    std::cout << "Index is: " << index << std::endl;
    return 0;
}

当我更改if子句(此处花费的时间的8%)使用less-than比较时,没有明显的性能提升:

if (!(_valToFind <  _sortedArr[midIndex]) == isAscending)

对此更改的反汇编的唯一区别是使用&#39; ja&#39;而不是jb。

任何想法都会受到赞赏。

2 个答案:

答案 0 :(得分:1)

也许尝试删除代码中的条件分支。

size_t luIndex[2] = { startIndex + 1, _len - 1 };
size_t &lowerIndex = luIndex[0];
size_t &upperIndex = luIndex[1]; 
size_t midIndex = 0;

// Binary search loop
while (upperIndex - lowerIndex > 1)
{
    midIndex = (upperIndex + lowerIndex) >> 1; // (upperIndex+lowerIndex)/2
    luIndex[_valToFind >= _sortedArr[midIndex] != isAscending] = midIndex;
}

return lowerIndex;

答案 1 :(得分:0)

你可以从循环中进行一次比较:

size_t findInArray(const double _sortedArr[], size_t _len, double _valToFind)
{
size_t startIndex = 0;

if( _len <= 1 ) return startIndex;

// Determine if the array is sorted ascending or descending
unsigned int isAscending = (_sortedArr[_len-1] > _sortedArr[startIndex]);
size_t lowerIndex = startIndex + 1;
size_t upperIndex = _len - 1;
size_t midIndex = 0;

// To avoid looping through the array, detect edge cases first
if( isAscending ) {
    if( _valToFind <  _sortedArr[startIndex+1] ) return startIndex;
    if( _valToFind >= _sortedArr[_len-1] ) return _len-1;

    // Binary search loop for isAscending == true
    while (upperIndex - lowerIndex > 1)
    {
        midIndex = (upperIndex + lowerIndex) >> 1; // (upperIndex+lowerIndex)/2
        if (_valToFind >=  _sortedArr[midIndex])
            lowerIndex = midIndex;
        else
            upperIndex = midIndex;
    }
} else {
    if( _valToFind >  _sortedArr[startIndex+1] ) return startIndex;
    if( _valToFind <= _sortedArr[_len-1] ) return _len-1;

    // Binary search loop for isAscending == false
    while (upperIndex - lowerIndex > 1)
    {
        midIndex = (upperIndex + lowerIndex) >> 1; // (upperIndex+lowerIndex)/2
        if (_valToFind >=  _sortedArr[midIndex])
            upperIndex = midIndex;
        else
            lowerIndex = midIndex;
    }
}

return lowerIndex;
}