目录
为什么要向量化什么是向量化如何向量化首先我们来了解一下数组的进阶用法数组切片批量赋值向量函数where语句来试试
[回到顶部](javascript:void(0);)
这是一篇我去年写的简单向量化教程,转上来放着吧。

为什么要向量化

想到这个问题是因为最近上机实习,写了不少代码,也看了不少人写的代码。实习常常写出这种代码。
do k=1,3 do i=1,180 do j=1,89 do it=1,55 num=num+ddi(it,k) aa=aa+sst_m(i,j,12*(it+2)+12)*ddi(it,k) sst_p(i,j,k)=aa bb=bb+sst_m(i,j,12*(it+2)+12) sstave(i,j)=bb end do ave_p(i,j,k)=sst_p(i,j,k)/num end do end do end do
这么多循环我要怎么看清楚谁是谁,谁又用来干什么。。。
然而这段已经是被精简过,且有良好缩进了,却依然较难看出每一个变量用来干什么。难道就没有什么办法再精简再让逻辑更加清晰吗?
这时候我们就需要向量化。
向量化有什么好处?
减少循环嵌套的层数,极大的精简我们的代码获得更加清晰的逻辑加快运算速度

什么是向量化

向量化计算是一种特殊的并行计算的方式。更多高深的解释语言我就不多说了,来我们看例子。
real A(144,72),B(144,72),R
A = 4.0
B = A2 + A*2 - A/2 + A
R = sum(B)
这就是所谓的向量化了

如何向量化

还是以上面那个例子来说
real A(144,72),B(144,72),C(10,10),r
A = 4.0
B = A2 + A*2 - A/2 + A
C = B(1:10,1:10)
A = cos(A)
r = sum(B)

首先我们来了解一下数组的进阶用法

数组切片
数组切片就是将一个更大的数组切成小一些的数组,就像切蛋糕一样。
我们先回忆一下,我们选取一个数组某一个值得时候怎么做的呢?比如我们要选取A数组的第三行第四列
的那个数值,我们会这样用A(3,4),这是数组的基本用法,相信大家都会用。
可是,如果我想选取A数组的第三行,第四第五两列的两个数据该怎么做呢?
我们可以使用A(3,4:5)
原来乳此! 那么B(1:10,1:10)的意思就是切取B数组的第一至十行,第一至十列共10行10列100个数据。
如果需要选所有行的第一列呢? 那我们不指定数组就好啦~ A(:,1)
批量赋值
A=4.0是什么?为什么一个标量可以对一个数组赋值?
我们可以看到A B都是维度为(144,72)的实数数组,r是一个实数
那么提问:通常情况下,要将一个数组赋值为0,要怎么做呢?
我知道我知道!用循环啊,这么简单的事怎么难得住我。
没错,如果你会C语言,第一想法肯定是用两个循环逐一赋值为0。
可是我们强大的fortran怎么能这么简易呢?
看到这里你肯定猜到了。
A = 4.0作用就是将A数组全部赋值为4.0,那么如果A = 0.0那么我们就能将A全部赋值为0了。
那A*2是什么呢?
A*2就是A的每个元素单独*2,结果与A同维度,跟数学中的矩阵与标量相乘类似。
同理,A**2是对A的每个元素单独求二次方,结果也同样与A同维度。
机智的同学可能已经猜出来了,A + A也与数学中矩阵运算相似,结果与2*A相等。
到这里,想必各位同学都清楚了,普通的运算符在两个同等维度的数组之间是逐元运算,
也就是对应位置的计算。标量与数组之间是广播运算,标量对数组全体起作用。
所有fortran内置函数均支持对数组进行逐元运算,就如A=cos(A)一样。
向量函数
sum()是什么呢?
就如这个函数的名字。sum函数是fortran自带的函数,用于数组求和。
最基础的用法即是r = sum(B),可以求得B数组所有元素的和。
sum的进阶用法
sum的进阶用法依赖于数组的进阶用法,聪明的同学想必已经想到了。我们可以有sum(A(:,10))这种用法。
我们可以使用sum的第二个参数指定加哪一个维度。
通常我们需要求取全球气温场的多年平均
real t(144,73,60),ave(144,73)
略过读取
ave = sum(t,3)/60.0
什么?一句话解决??
是的没错就是一句话解决
通过给sum函数指定求和维度,sum(t,3)等价于
do i=1,144
do j=1,73
sum(i,j,:)
end do
end do
where语句
再来考虑一下以下场景:
sst(144,73)是一个多年平均海表温度场,其中陆地格点的值为999。现在我们需要把陆地格点的值替换为0,同时将mask(144,73)中相同位置的数据置为1。
通常情况下还是会使用一个两层嵌套进行遍历,然后将符合条件的格点进行处理。
这种情况我们可以使用where语句
where(sst==999)
sst = 0
mask = 1
end where
怎么能这么短。。。。!

来试试

你可以尽量用你能接受的方式来逐步向量化,不一定需要一步就去掉所有的循环。加油
t1(144,73,12)是某一年的每月平均气温,我们需要求取全年平均气温,应该怎么写呢?条件接上题,需要这一年的夏季平均气温,现在该怎么写呢?t2(144,73,12,61)是61年的每月平均气温,我们需要求取每个月61年平均气温,应该怎么写呢?条件接上题,现在我们需要61年春季的平均气温,该怎么写呢?R(144,73)是某一个场r检验的值,现在我们需要将R中大于2.1的元素对应位置的sig(144,73)赋值为1,
其余部分赋值为0,该怎么写?