C++ 是否可以进行微观优化;x=最大值(a,b);y=最小值(a,b)&引用;?

C++ 是否可以进行微观优化;x=最大值(a,b);y=最小值(a,b)&引用;?,c++,algorithm,c++11,optimization,bit-shift,C++,Algorithm,C++11,Optimization,Bit Shift,我有一个算法,一开始就像 int sumLargest2 ( int * arr, size_t n ) { int largest(max(arr[0], arr[1])), secondLargest(min(arr[0],arr[1])); // ... 我意识到,第一个可能不是最优的,因为调用 max ,然后 min 是重复的,当你认为知道最小值的信息在找到最大值后就已经存在了。所以我想我能做到 int largest = max(arr[0], arr[1]

我有一个算法,一开始就像

int sumLargest2 ( int * arr, size_t n )
{
    int largest(max(arr[0], arr[1])), secondLargest(min(arr[0],arr[1])); 
    // ... 

我意识到,第一个可能不是最优的,因为调用<代码> max ,然后<代码> min 是重复的,当你认为知道最小值的信息在找到最大值后就已经存在了。所以我想我能做到

   int largest = max(arr[0], arr[1]);
   int secondLargest = arr[0] == largest ? arr[1] : arr[0];
删除了对
min
的无用调用,但我不确定这是否真的可以保存任何数量的操作。有没有什么奇特的位移位算法可以达到

int largest(max(arr[0], arr[1])), secondLargest(min(arr[0],arr[1]));
???

怎么样:

int largestIndex = arr[1] > arr[0];
int largest = arr[largestIndex];
int secondLargest = arr[1 - largestIndex];

第一行依赖布尔结果的隐式转换,在真值的情况下,1为0,在C++中为

< P>,可以使用最小值和最大值生成<代码> STD::配对< /代码>。这与以下因素结合起来尤其容易:

#包括
#包括
int最大,第二大;
std::tie(第二大,最大)=std::minmax(arr[0],arr[1]);
GCC至少能够将对minmax的调用优化为单个比较,与下面的C代码的结果相同

在C语言中,您可以自己编写测试:

int largest, secondLargest;
if (arr[0] < arr[1]) {
  largest = arr[1];
  secondLargest = arr[0];
} else {
  largest = arr[0];
  secondLargest = arr[1];
}
int最大,次大;
if(arr[0]
如果您打算减少函数调用以查找最小mad max,您可以尝试
std::minmax\u元素
。这是从C++11开始提供的

auto result = std::minmax_element(arr, arr+n);
std::cout<< "min:"<< *result.first<<"\n";
std::cout<< "max :" <<*result.second << "\n";
auto result=std::minmax_元素(arr,arr+n);

std::cout如果您只想找到两个值中的较大值,请执行以下操作:

if(a > b)
{
    largest = a;
    second = b;
}
else
{
     largest = b;
     second = a;
}

没有函数调用,一次比较,两次赋值。

我假设您更愿意解决更大的问题。。。也就是说,获取数组中最大两个数的和

你所要做的是一件好事。 让我们实施它

int sumLargest2(int * arr, size_t n) {
    int * first  = arr;
    int * middle = arr + 2;
    int * last   = arr + n;

    std::partial_sort(first, middle, last, std::greater<int>());

    return arr[0] + arr[1];
}
int sumlatest2(int*arr,size\n){
int*first=arr;
int*middle=arr+2;
int*last=arr+n;
std::partial_排序(第一、中间、最后,std::greater());
返回arr[0]+arr[1];
}

如果您无法修改arr,那么我建议您进行研究。

时间-空间权衡如何

#include <utility>

template<typename T>
    std::pair<T, T>
        minmax(T const& a, T const& b)
        { return b < a ? std::make_pair(b, a) : std::make_pair(a, b); }

//main
std::pair<int, int> values = minmax(a[0], a[1]);
int largest       = values.second;
int secondLargest = values.first;
#包括
模板
std::pair
最小最大值(T常数和a、T常数和b)
{返回b
它不一定会更快,但会有所不同

也要注意溢出。< /P> < P>我假设C++ +…/P> 简短回答,使用std::minmax并使用正确的优化和正确的指令集参数进行编译

长而难看的答案,编译器无法做出所有必要的假设,以使其真正、真正快速。你可以。在这种情况下,您可以将算法更改为首先处理所有数据,并且可以强制对数据进行对齐。完成所有这些,您可以使用intrinsics使其更快

虽然我还没有在这个特定的案例中测试它,但我已经看到使用这些准则可以极大地提高性能

由于您没有向函数传递2个整数,因此我假设您使用的是数组,并希望以某种方式对其进行迭代。现在您可以选择:创建2个数组并使用最小/最大值,或者将1个数组与
a
b
一起使用。这一决定本身就可能影响性能

如果有2个数组,则可以在32字节边界上使用对齐的malloc分配这些数组,然后使用intrinsic进行处理。如果你想要真正的,原始的表现,这是一条路要走

假设你有AVX2。(注意:我不确定您是否这样做,您应该使用CPU id检查!)。点击这里的备忘单:选择你的毒药

在这种情况下,您要寻找的本质可能是:

  • _mm256_min_epi32
  • _mm256\u最大值\u epi32
  • _mm256\流\加载\ si256
如果必须对整个数组执行此操作,则可能需要在合并单个项之前将所有内容保存在一个_mm256寄存器中。例如:每256位向量执行一个最小/最大值,循环完成后,提取32位项并对其执行一个最小/最大值

很长很好的回答:所以。。。至于编译器。编译器确实试图优化这些类型的东西,但是遇到了问题

如果您处理两个不同的数组,编译器必须知道它们是不同的,以便能够对其进行优化。这就是为什么像这样的东西存在的原因,它告诉编译器在编写代码时您可能已经知道的这一点

而且,编译器不知道你的内存是否对齐,所以它必须检查这一点并进行分支。。。每次打电话。我们不想这样;这意味着我们想让它内嵌它的内容。所以,添加
inline
,将其放入头文件,就这样。您还可以使用
aligned
给他一个提示

您的编译器也没有得到
int*
不会随时间变化的提示。如果无法更改,最好告诉他使用
const
关键字

编译器使用指令集进行编译。通常,它们已经使用了SSE,但AVX2可以提供很多帮助(正如我在上面的intrinsic中所展示的)。如果您可以使用这些标志编译它,请确保使用它们-它们非常有用

在发布模式下运行,使用“fast”上的优化进行编译,然后查看引擎盖下发生了什么。如果执行所有这些操作,您应该会看到
vpmax…
指令出现在内部循环中,这意味着编译器可以很好地使用内部函数


我不知道你在循环中还想做什么。。。如果您使用所有这些指令,您应该可以在大型阵列上达到内存速度。

您的基准测试显示了多少瓶颈
#include <utility>

template<typename T>
    std::pair<T, T>
        minmax(T const& a, T const& b)
        { return b < a ? std::make_pair(b, a) : std::make_pair(a, b); }

//main
std::pair<int, int> values = minmax(a[0], a[1]);
int largest       = values.second;
int secondLargest = values.first;
x = max(a, b);
y = a + b - x;