将一个数组转换为一个标量的计算称为约简操作。典型的约简操作有矢量元素的求和或求积。违反循环中计算标准的约简操作不能在各次迭代间以累积方式改变标量变量。
示例:向量元素的约简求和:
s = 0.0 do i = 1, 1000 s = s + v(i) end do t(k) = s |
但是,对于某些操作,如果约简是阻止并行化的唯一因素,仍然可以对循环进行并行化。常见约简操作出现频率很高,因而编译器能够将其视为特例进行并行化。
自动并行化分析不包括约简操作的识别,除非随 -autopar 或 -parallel 一同指定了 -reduction 编译器选项。
如果某一可并行化的循环包含表 10–2 中列出的某一项约简操作,则当指定了 -reduction 时,编译器将会对其进行并行化。
下表列出了编译器识别的约简操作。
表 10–2 识别的约简操作
数学运算 |
Fortran 语句模板 |
---|---|
求和 |
s = s + v(i) |
求积 |
s = s * v(i) |
点积 |
s = s + v(i) * u(i) |
最小值 |
s = amin( s, v(i)) |
最大值 |
s = amax( s, v(i)) |
OR |
do i = 1, n b = b .or. v(i) end do |
AND |
b = .true. do i = 1, n b = b .and. v(i) end do |
非零元素计数 |
k = 0 do i = 1, n if(v(i).ne.0) k = k + 1 end do |
识别所有形式的 MIN 和 MAX 函数。
计算并行执行的顺序与在单个处理器上串行执行的顺序不同。
计算顺序会影响浮点型数的求和或求积。硬件浮点加法和乘法不是结合式的。可能会出现舍入、溢出或下溢误差,具体取决于操作数关联的方式。例如,(X*Y)*Z 和 X*(Y*Z) 可能会得出不同的有效数。
在一些情况下,该误差是不能接受的。
示例:舍入,求介于 –1 和 +1 之间的 100,000 个随机数之和:
demo% cat t4.f parameter ( n = 100000 ) double precision d_lcrans, lb / -1.0 /, s, ub / +1.0 /, v(n) s = d_lcrans ( v, n, lb, ub ) ! Get n random nos. between -1 and +1 s = 0.0 do i = 1, n s = s + v(i) end do write(*, ’(" s = ", e21.15)’) s end demo% f95 -O4 -autopar -reduction t4.f |
结果会随着处理器的个数而变化。下表展示了介于 – 1 和 +1 之间的 100,000 个随机数之和。
处理器数 |
输出 |
---|---|
1 |
s = 0.568582080884714E+02 |
2 |
s = 0.568582080884722E+02 |
3 |
s = 0.568582080884721E+02 |
4 |
s = 0.568582080884724E+02 |
在这种情况下,对于随机开始的数据而言,10-14 阶的舍入误差是可以接受的。有关更多信息,请参见 Sun《数值计算指南》。