Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/133.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在两种条件下优化阵列元素的比较;C++;抽象机制?_C++_Optimization_C++11_Visitor_C++ Standard Library - Fatal编程技术网

C++ 在两种条件下优化阵列元素的比较;C++;抽象机制?

C++ 在两种条件下优化阵列元素的比较;C++;抽象机制?,c++,optimization,c++11,visitor,c++-standard-library,C++,Optimization,C++11,Visitor,C++ Standard Library,我的问题是一个后续的问题,它已经被搁置(不愉快)。问题是优化带有浮点数的数组上的循环,测试浮点数是否在给定的间隔内。数组中匹配元素的索引将存储在提供的结果数组中 测试包括两个条件(小于上限阈值和大于下限阈值)。测试的明显代码是if(elem=lower).。我观察到分支(包括短路运算符&&)比第二次比较要昂贵得多。下面是我的想法。它比简单的实现快20%-40%,比我预期的要多。它使用bool是整数类型这一事实。条件测试结果用作两个结果数组的索引。其中只有一个包含所需的数据,另一个可以丢弃。这将用

我的问题是一个后续的问题,它已经被搁置(不愉快)。问题是优化带有浮点数的数组上的循环,测试浮点数是否在给定的间隔内。数组中匹配元素的索引将存储在提供的结果数组中

测试包括两个条件(小于上限阈值和大于下限阈值)。测试的明显代码是
if(elem=lower).
。我观察到分支(包括短路运算符&&)比第二次比较要昂贵得多。下面是我的想法。它比简单的实现快20%-40%,比我预期的要多。它使用bool是整数类型这一事实。条件测试结果用作两个结果数组的索引。其中只有一个包含所需的数据,另一个可以丢弃。这将用数据结构和计算取代程序结构

我对优化的更多想法感兴趣。“技术黑客”(这里提供的那种)是受欢迎的。我还感兴趣的是,现代C++是否能够提供更快的方法,例如,通过使编译器能够创建并行运行的代码。想想访问者模式/函子。对单个srcArr元素的计算几乎是独立的,只是结果数组中索引的顺序取决于测试源数组元素的顺序。我会稍微放宽一些要求,这样结果数组中报告的匹配索引的顺序就无关紧要了。有人能想出一个快速的方法吗

下面是函数的源代码。下面是一条支撑干管。由于chrono,gcc需要-std=c++11。VS2013 express也能够编译这个(并且创建的代码比gcc-O3快40%)

#包括
#包括
#包括
使用名称空间std;
使用名称空间std::chrono;
///检查srcArr中的所有元素是否位于
///间隔[下,上]。存储
///destArr[1]指向的数组中的此类元素
///并返回找到的匹配元素数。
///这是高度优化的,主要是为了避免分支。
int findelemsinterval(const float srcArr[],//包含候选项
int**const destArr,//要用索引填充的两个数组
const int arrLen,//每个数组的长度
恒浮下限,恒浮上限//间隔
)
{
//使用条件代替分支
//作为两个不同数组的索引。我们需要
//这两个数组都有单独的索引。
国际命运[2];
目的地[0]=目的地[1]=0;

对于(int srcInd=0;srcInd考虑整数范围检查优化转动a我看到大约10%的加速:

int destIndex = 0;  // replace destIndices

int isInInterval = (srcArr[srcInd] <= upper) == (srcArr[srcInd] >= lower);
destArr[1][destIndex] = srcInd;
destIndex += isInInterval;
int destIndex=0;//替换destIndex
int isInInterval=(srcArr[srcInd]=更低);
destArr[1][destIndex]=srcInd;
destIndex+=isInInterval;

消除这对输出数组。如果要保留结果,只需将“写入的数字”提前1,否则只需继续覆盖“结束后的数字”索引

即,
retval[destinex]=curIndex;destinex+=isInArray;
——更好的一致性和更少的内存浪费

编写两个版本:一个支持固定数组长度(比如1024或任何长度),另一个支持运行时参数。使用
template
argummt删除代码重复。假设长度小于该常量

具有函数返回大小和RVO'd
std::array


编写一个合并结果的包装函数(创建所有结果,然后合并它们)。然后抛出Parralel patterns库来解决问题(这样可以在Parralel中计算结果)。

如果您允许自己使用SSE(或更好的AVX)进行矢量化在指令集中,您可以一次执行4/8比较,执行两次“和”结果,并检索4个结果(-1或0)。同时,这将展开循环

// Preload the bounds
__m128 lo= _mm_set_ps(lower);
__m128 up= _mm_set_ps(upper);

int srcIndex, dstIndex= 0;

for (srcInd= 0; srcInd + 3 < arrLen; )
{
  __m128 src= _mm_load_ps(&srcArr[srcInd]); // Load 4 values
  __m128 tst= _mm_and_ps(_mm_cmple_ps(src, lo), _mm_cmpge_ps(src, up)); // Test

  // Copy the 4 indexes with conditional incrementation
  dstArr[dstIndex]= srcInd++; destIndex-= tst.m128i_i32[0];
  dstArr[dstIndex]= srcInd++; destIndex-= tst.m128i_i32[1];
  dstArr[dstIndex]= srcInd++; destIndex-= tst.m128i_i32[2];
  dstArr[dstIndex]= srcInd++; destIndex-= tst.m128i_i32[3];
}
//预加载边界
__m128 lo=_mm_set_ps(下部);
__m128向上=_mm_set_ps(上部);
int SRCDINDEX,DSTDINDEX=0;
对于(srcInd=0;srcInd+3

警告:未选中的代码。

在整数算术中,您可以在2-补码体系结构上使用溢出来打开范围检查
a@Peter G…。很好。现在是浮动;-)。添加
-funroll循环可以多减少20%左右。不,这在两个方面是不好的。首先,转换为浮点会失去准确性,其次,浮点比整数慢得多。@Skizz:我的问题是浮点,所以这个主意很好。但不确定晶圆厂的成本有多高。@PeterSchneider:oops,错过了,Peter G的公司mment side稍微动了动我的脑筋。虽然边界之间存在很大差异,但问题仍然存在准确性问题。不错,晶圆厂显然很便宜。大优化(20-30%)。我还将我的实现切换到一个向量,不幸的是,该向量的访问成本略高于普通数组。您的算法只需要一个元素访问,这可能会有所贡献。哦,有点明显,现在您已经向我展示了;-)。Tony在“写入的数字”方面比您领先30秒想法:-)。-我将研究MS的并行模式库,谢谢。这与我所想的方向有很大的不同。(显然,可以手动并行,但我是
int destIndex = 0;  // replace destIndices

int isInInterval = (srcArr[srcInd] <= upper) == (srcArr[srcInd] >= lower);
destArr[1][destIndex] = srcInd;
destIndex += isInInterval;
// Preload the bounds
__m128 lo= _mm_set_ps(lower);
__m128 up= _mm_set_ps(upper);

int srcIndex, dstIndex= 0;

for (srcInd= 0; srcInd + 3 < arrLen; )
{
  __m128 src= _mm_load_ps(&srcArr[srcInd]); // Load 4 values
  __m128 tst= _mm_and_ps(_mm_cmple_ps(src, lo), _mm_cmpge_ps(src, up)); // Test

  // Copy the 4 indexes with conditional incrementation
  dstArr[dstIndex]= srcInd++; destIndex-= tst.m128i_i32[0];
  dstArr[dstIndex]= srcInd++; destIndex-= tst.m128i_i32[1];
  dstArr[dstIndex]= srcInd++; destIndex-= tst.m128i_i32[2];
  dstArr[dstIndex]= srcInd++; destIndex-= tst.m128i_i32[3];
}