英特尔 MKL 或某些类似的库是否提供了一种矢量化方法来计算满足 C 中某些条件的数组中的元素数量?

Does Intel MKL or some similar library provide a vectorized way to count the number of elements in an array fulfilling some condition in C?

问题

我正致力于使用一些相当大的数组(从数千万个浮点数及以上)实现和改进优化算法,并主要使用 C 中的英特尔 MKL(不是 C++,至少目前还没有)来压缩发挥出每一个可能的表现。现在我 运行 遇到了一个愚蠢的问题 - 我有一个参数可以为一组(数千万)系数的子集设置最大值和最小值。实际上,使用 MKL 函数应用这些最大值和最小值很容易——我可以为每个元素创建具有限制的大小相等的向量,并使用 V?Fmax 和 V?Fmin 来应用它们。但我还需要在我的错误指标中考虑这种裁剪,这需要我计算超出这些限制的元素数量。

但是,我找不到一个 MKL 函数可以让我做一些事情,比如计算满足某些条件的元素的数量,你可以用例如创建和求和逻辑数组的方式Python 或 MATLAB 中的 NumPy。令人恼火的是,当我尝试 google 这个问题时,我只得到与 Python 和 R.

有关的答案

显然,我可以编写一个循环,为满足其中一个条件的每个元素递增一个计数器,但是如果有一个已经优化的实现可以让我实现这一点,我更愿意这样做,因为我的阵列的大小。

有谁知道使用英特尔 MKL(可能使用统计工具箱或对基本函数的一些创造性使用?)、执行此操作的类似优化库或高度优化的库来稳健且非常有效地实现此目的的巧妙方法手动编码的方法?我一直在绞尽脑汁试图想出一些开箱即用的方法,但我一无所获。

请注意,我有必要在 C 中执行此操作 ,我无法将此任务转移到我的 Python 前端,并且我确实有必要首先用 C 编写这个特定的子程序。

谢谢!

如果您使用的是 c++,算法库中的 count_if 执行策略 par_unseq 可能会并行化和矢量化计数。至少在 Linux 上,它通常使用 Intel TBB 来执行此操作。

在 c 中不太可能那么容易。因为 c 没有模板、可调用对象或 lambda 等概念,所以专门化通用(库提供)count() 函数的唯一方法是将函数指针作为回调传递(如 qsort()做)。除非编译器设法去虚拟化和内联回调,否则您根本无法矢量化,留下(可能是线程并行化的)标量代码。 OTOH,如果你使用例如 gcc vector intrinsics(我最喜欢的!),你会得到矢量化而不是并行化。您可以尝试结合这些方法,但我会说克服自己并使用 c++。

但是,如果您只需要矢量化,您几乎可以肯定只编写顺序代码并让编译器自动矢量化,除非应该计算的谓词写得不好,或者您的编译器脑残。

example。如果至少有 sse4 指令可用 (-msse4),gcc 会在 x86 上矢量化代码。使用 AVX[2/512] (-mavx / -mavx2 / -mavx512f),您可以获得更宽的向量来同时处理更多元素。一般来说,如果您在相同的硬件上编译,您将 运行 程序,我建议让 gcc 自动检测最佳指令集扩展 (-march=native)。

请注意,在提供的代码中,条件应该使用短路或(||),因为然后从max读取如果与 min-vector 的比较对于当前元素已经为真,则 -vector 在语义上被禁止,严重阻碍了矢量化(尽管 avx512 可能 可能会以某种灾难性的速度将其矢量化) .

我很确定 gcc 在它为 avx512 生成的代码中几乎不是最优的,因为它可以在掩码寄存器中执行 k-reg(掩码寄存器)or kor[b/w/d/q],但也许在 avx512 方面有更多经验的人(*cougth* Peter Cordes *cough*)可以权衡一下。

MKL 不提供此类函数,但您可以尝试检查另一个性能库 - IPP,它包含一组可能对您的情况有用的阈值函数。请参阅 IPP 开发人员参考以查看更多详细信息 - https://software.intel.com/content/www/us/en/develop/documentation/ipp-dev-reference/top/volume-1-signal-and-data-processing/essential-functions/conversion-functions/threshold.html