是否可以微观优化“x = max(a,b); y = min(a,b);”?

时间:2015-05-20 15:21:15

标签: 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 secondLargest = arr[0] == largest ? arr[1] : arr[0];

去除min无用的调用,但我不确定实际上是否会保存任何数量的操作。是否有任何奇特的位移算法可以完成相同的

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

···

8 个答案:

答案 0 :(得分:10)

在C ++中,您可以使用std::minmax生成最小值和最大值SELECT Person.FirstName, Person.LastName, Person.Phone, Person.Email, Person.Address, Count(*) as Result <br> From Table1 join table 2 -- etc <br> WHERE a = b -- etc <BR> GROUP BY Person.FirstName, Person.LastName, Person.Phone, Person.Email, Person.Address 。与std::tie

结合使用时尤为简单
std::pair

GCC至少能够将对minmax的调用优化为单个比较,与下面的C代码的结果相同。

在C中,你可以自己编写测试:

#include <algorithm>
#include <utility>

int largest, secondLargest;
std::tie(secondLargest, largest) = std::minmax(arr[0], arr[1]);

答案 1 :(得分:4)

怎么样:

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

第一行依赖于布尔结果的隐式强制转换,在真实的情况下为1,在假的情况下为0。

答案 2 :(得分:4)

如果您打算减少函数调用以查找min mad max,则可以尝试std::minmax_element。这是从C ++ 11开始提供的。

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

答案 3 :(得分:4)

我会假设您宁愿解决更大的问题......也就是说,得到数组中最大的两个数字之和。

您要做的是std::partial_sort()。 让我们来实现它。

$route['auth/(:any)/(:num)'] = "bit_auth/$1/$2";

如果您无法修改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]; } ,那么我建议您查看std::partial_sort_copy()

答案 4 :(得分:4)

x = max(a, b);
y = a + b - x;

它不一定会更快,但会有所不同。

还要注意溢出。

答案 5 :(得分:3)

如果您只想找到两个值中较大的值,请执行:

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

无函数调用,一次比较,两次分配。

答案 6 :(得分:2)

如何进行时空权衡?

zip_code   city
210        Boston
211        Boston
212          .
1431         .

答案 7 :(得分:2)

我假设是C ++ ......

简短回答,使用std :: minmax并使用正确的优化和正确的指令集参数进行编译。

长期难看的答案,编译器无法做出必要的所有假设,以使其真正,非常快。您可以。在这种情况下,您可以更改算法以首先处理所有数据,并且可以强制对齐数据。完成所有这些操作后,您可以使用内在函数来加快速度。

虽然我没有在这种特殊情况下测试它,但我已经看到使用这些指南的巨大性能改进。

由于你没有将2个整数传递给函数,我假设你使用了一个数组,并想以某种方式迭代它。您现在可以选择:制作2个数组并使用最小值/最大值或使用1个阵列同时使用ab。仅这一决定已经可以影响绩效。

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

F.ex,我们假设你有AVX2。 (注意:我不确定你是否这样做,你应该使用CPU ID来检查它!)。转到这里的备忘单:https://software.intel.com/sites/landingpage/IntrinsicsGuide/并挑选你的毒药。

您正在寻找的内在函数可能是:

  • _mm256_min_epi32
  • _mm256_max_epi32
  • _mm256_stream_load_si256

如果必须为整个数组执行此操作,则可能需要在合并各个项之前将所有内容保留在单个__mm256寄存器中。例如:每256位向量执行一次最小值/最大值,当循环完成时,提取32位项并对其进行最小值/最大值。

更好的答案:所以...至于编译器。编译器会尝试优化这些类型的东西,但会遇到问题。

如果您处理了2个不同的数组,编译器必须知道它们是不同的才能进行优化。这就是为什么像restrict这样的东西存在的原因,它告诉编译器你编写代码时可能已经知道的这个小东西。

此外,编译器不知道您的内存是否已对齐,因此必须检查此内容并为每次调用分支....我们不希望这样;这意味着我们希望它能够内联它的内容。所以,添加inline,将其放在头文件中即可。您也可以使用aligned给他一个提示。

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

编译器使用指令集进行编译。通常情况下,他们已经使用了SSE,但AVX2可以提供很多帮助(正如我上面用内在函数所示)。如果可以使用这些标志进行编译,请确保使用它们 - 它们有很多帮助。

在发布模式下运行,在'fast'上进行优化编译,看看底层会发生什么。如果你这样做,你应该看到内部循环中出现vpmax...指令,这意味着编译器使用内在函数就好了。

我不知道你想在循环中做什么...如果你使用所有这些指令,你应该在大数组上达到内存速度。