在一个数组中查找具有最小绝对值的元素

时间:2016-01-10 12:30:06

标签: c++

我试图在一个数组中找到一个具有最小绝对值的元素。例如,在数组[5.1,-2.2,8.2,-1,4,3,-5,6]中,我想得到值-1。我使用以下代码( myarray 是1D数组而未排序)

for (int i = 1; i < 8; ++i)
    {
        if(fabsf(myarray[i])<fabsf(myarray[0])) myarray[0] = myarray[i];
    }

然后,目标值在 myarray [0] 中。 因为我必须多次重复这个过程,所以这段代码成为我程序的瓶颈。有谁知道如何改进此代码?提前致谢!

顺便说一下,阵列的大小总是 8 。这可以用来优化这段代码吗?

更新:到目前为止,以下代码在我的机器上运行稍微好一些:

float absMin = fabsf(myarray[0]); int index = 0; 
for (int i = 1; i < 8; ++i)
    {
        if(fabsf(myarray[i])<absMin) {absMin = fabsf(myarray[i]); index=i;}
    }
float result = myarray[index];

我在徘徊如何避免 fabsf ,因为我只想比较绝对值而不是计算它们。有谁有想法吗?

5 个答案:

答案 0 :(得分:1)

让我提出一些可能有所帮助的想法:

float minVal = fabsf(myarray[0]);
for (int i = 1; i < 8; ++i)
{
    if(fabsf(myarray[i])<minVal) minVal = fabsf(myarray[i]);
}

myarray[0] = minVal;

但是现在的编译器非常聪明,你可能无法获得更高的速度,因为你已经获得了优化的代码。这取决于你提到的代码段的调用方式。

优化可能的另一种方法是使用C ++和STL,因此您可以使用典型的二叉搜索树std::set执行以下操作:

// Absolute comparator for std::set
bool absless_compare(const int64_t &a, const int64_t &b) 
{
   return (fabsf(a) < fabsf(b));
}

std::set<float, absless_compare> mySet = {5.1, -2.2, 8.2, -1, 4, 3, -5, 6};

const float minVal = *(mySet.begin());

通过插入数字这种方法,它们已经按升序排序。较小的比较器通常是std :: set的集合,但您可以将其更改为使用与此示例中不同的内容。这可能对较大的数据集有所帮助,但是你提到你只有八个要比较的值,所以它实际上没有帮助。

八个元素是一个非常小的数字,可以保留在堆栈中,例如在填充数据之前,std::array<float,8> myarray的声明靠近排序函数。您应该在完整代码集上使用这些变体并观察有什么帮助。当然,如果您声明std::array<float,8> myarrayfloat[8] myarray运行时,您应该得到相同的结果。

您还可以检查的是fabsf是否真的使用float作为参数,并且不会将您的变量转换为double会降低性能。还有std::abs()我的理解推断出数据类型,因为在C ++中你可以使用模板等。

如果不想使用fabs显然是这样的呼叫

float myAbs(const float val)
{
   return (val<0) ? -val : val;
}

或者你把这个数字归零,这会使你的数字为负数。无论哪种方式,我很确定,fabsf完全了解这一点,我认为这样的代码不会让它更快。

所以我会检查参数是否转换为double。如果您的系统中有C99 Standard,则不应该出现此问题。

答案 1 :(得分:1)

有一些城市神话,如内联,循环展开和类似的,这应该会使你的代码更快。好消息是你不必这样做,至少如果你使用-O3编译器优化。

坏消息是,如果您已经使用-O3,那么您无法做任何事情来加速此功能:编译器将优化您的代码!例如,它肯定会像某些人所建议的那样对fabsf(myarray[0])进行缓存。你能做到的唯一一件就是&#34;重构&#34;是在程序中构建错误并使其可读性降低。

我的建议是到其他地方寻求改进:

  1. 尝试减少此代码的调用次数
  2. 如果这个代码是瓶颈,那么我的猜测就是你一遍又一遍地重新计算最小值(否则将值填入数组需要大约相同的时间) - 所以缓存搜索结果< / LI>
  3. 将成本转移到更改数组的元素,例如通过使用一些奇特的数据结构(堆,priority_queue)或跟踪最少的元素。假设您的数组只有两个元素值[1,2],因此最小值为1。现在如果你改变了
    • 2到3,你不必做任何事情
    • 2到0,您可以轻松地将最小值更新为0
    • 1到3,你必须遍历所有元素。但也许这种情况不常见。

答案 2 :(得分:1)

你能存储预制的价值吗?

同样正如@Gerstrong所提到的那样,将数字存储在循环外部并且只在数组更改时计算它将为您提供支持。

调用partial_sortnth_element只会对数组进行排序,以使正确的值位于正确的位置。

std::nth_element(v.begin(), v.begin(), v.end(), [](float& lhs, float& rhs){
    return fabsf(lhs)<fabsf(rhs);
});

答案 3 :(得分:0)

一种想法是进行比较“比赛”风格,而不是线性。换句话说,你首先将1与2,3,4与4等进行比较。然后你取出这4个元素并做同样的事情,然后再次,直到你只剩下一个元素。

这不会改变比较次数。由于每次比较都会从跑步中消除一个元素,无论如何都会有7个比较。那么为什么我建议呢?因为它从代码中删除了数据依赖性。现代处理器具有多个流水线,可以同时退出多个指令。但是,当您在循环中进行比较时,每个循环迭代都取决于前一个循环。当你做锦标赛风格时,前四个比较是完全独立的,所以处理器可以一次完成所有这些。

除此之外,您还可以在一个简单的循环中一次计算所有晶圆厂,并将其放入一个新的阵列中。由于晶圆厂的计算是独立的,因此可以很容易地加速。你会先做这个,然后比赛风格比较得到索引。它应该是完全相同的操作数,它只是改变了顺序,以便编译器可以更容易地看到缺少数据依赖性的更大的块。

答案 4 :(得分:0)

  

具有最小绝对值的数组元素

让数组A

A = [5.1, -2.2, 8.2, -1, 4, 3, -5, 6]

A的最小绝对值为

double miniAbsValue = A.array().abs().minCoeff();
int i_minimum = 0;  // to find the position of minimum absolute value
for(int i = 0; i < 8; i++)
 {
  double ftn = evalsH(i);
  if( fabs(ftn) == miniAbsValue )
    {
      i_minimum =  i; 
    }
  }

现在A中具有最小绝对值的元素是

A(i_minimum)