为什么使用浮点数进行向量化比使用双精度浮点数更有效?

5

我注意到在C程序中向量化循环时,使用浮点数操作数比双精度操作数获得的加速更大。

例如:

for (int i = 0; i < N; i++) {
    a[i] += b[i] * c[i];
}    

当a、b和c的数组大小为20,000时,如果我重复执行这个循环1,000,000次:
- 没有使用矢量化,浮点数和双精度运行时间约为24秒。 - 使用自动矢量化(编译选项:-O1 -ftree-vectorize),浮点数运行时间约为7秒,双精度运行时间约为21秒。 - 使用OpenMP(# pragma omp simd)与上述情况类似。
可能的原因是什么?
编辑: 进一步信息:
- 处理器: Intel Core i7-2677M CPU @ 1.80GHz - 周围的代码除了分配数组(使用calloc)和一个循环,用于将数组b和c填充为常量值之外,没有其他任何代码。

4
什么处理器?它有哪些SIMD功能? 它的性能特征是什么?很可能,它的“float” SIMD指令每个指令操作的元素数量是其“double” SIMD指令的两倍。内存速度有多快?周围的代码是什么 - 编译器是否知道'a'、'b'和'c'可能重叠? - Eric Postpischil
谢谢。我已经添加了一些进一步的信息,但是我不确定如何回答所有问题,很抱歉。 - Dreana
1
请记住,现代CPU中的主要瓶颈通常是RAM带宽;即使您的CPU可以快速地将两个值相乘,如果它花费90%的时间等待这些值从RAM中获取,那么这并不重要。而且,双精度数组比等效的单精度数组大两倍,因此可能需要更多地从RAM中获取数据(与已经存在于CPU本地缓存中的所需数据相比)。 - Jeremy Friesner
2
三个包含20000个元素的float数组总共占用234 KiB,适合单核L2数据缓存。而三个double数组占用469 KiB,无法适应L2数据缓存。此外,使用float时,可以在一个向量寄存器中容纳8个元素,而使用double则减半,因此你只能获得一半的FLOPS。 - Hristo Iliev
2个回答

1

在许多这些操作中,使用SIMD(单指令,多数据)指令。浮点数的大小是双精度浮点数的一半,因此可以在一次指令中处理两倍的浮点数。然而,我很惊讶使用浮点数的速度是双倍以上而不是简单地加倍。我怀疑(但不确定)这是由于浮点数更容易操作 - 实际尾数提取等。


我想我明白你的意思 - 但是如果没有向量化的应用,这不也会显著影响计算时间吗? - Dreana

0
你尝试过使用-ffast-math选项吗?这可能会产生其他副作用,你需要进一步了解(例如潜在的精度损失)。

谢谢您的建议。我刚刚尝试了使用双精度浮点数,但在这种情况下计算时间并没有改变。 - Dreana
请查看Intel的这篇文章此处。它似乎很实用,特别是其中提到的“并非所有运算符都支持32位,这意味着除非使用较小的操作数,否则某些源代码将无法进行矢量化。”部分。 - PiMaker0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接