我试图在一个数组中找到一个具有最小绝对值的元素。例如,在数组[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 ,因为我只想比较绝对值而不是计算它们。有谁有想法吗?
答案 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> myarray
或float[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]
,因此最小值为1
。现在如果你改变了
0
答案 2 :(得分:1)
你能存储预制的价值吗?
同样正如@Gerstrong所提到的那样,将数字存储在循环外部并且只在数组更改时计算它将为您提供支持。
调用partial_sort
或nth_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)