我有一个函数,它使用二进制搜索在排序的双精度数组中查找索引,以便"搜索值"如果按升序排序,则大于或等于该索引处数组中的值,但严格小于后续索引处数组中的值。输入数组可以按升序或降序排序。
我在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。
任何想法都会受到赞赏。
答案 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;
}