新的公开免费使用的intel fortran编译器(ifx)采用了新的LLVM编译器,如果仍然使用和
原来的ifort一致的编译选项,则可能造成部分代码运行时数值结果相差悬殊。这里以自由振荡
计算特征函数为例,阐述这一数值差异。
自由振荡程序采用北京大学赵里教授全球地震学课上使用的Mineos代码,其使用说明中采用的ifort
编译选项为:
1
| ifort -O4 -c -132 -zero -save -o
|
若我们用ifx编译器采用同样的编译选项,即
1
| ifx -O4 -c -132 -zero -save -o
|
编译完成后,设置输入参数如下:
1
2
3
4
5
6
7
| GRAV="2000."
LMIN="1"
LMAX="2000"
EPS="1.d-11"
FMIN="-1."
FMAX="150."
CHKERR="1.d-2"
|
运行代码后,查看tmp目录下的特征函数,例如more ./tmp/PREMQL6ic_21808e_sph_0000001.fre,可能显示
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| 2 S 1 0.4412757 70.23120 14.23869 239.0774 0.3859189E-01 -0.1561984E-05 10.58604
3 S 1 0.5927955E-02 0.9434634 1059.925 1.402977 4.421282 -14.76647 2.123659
4 S 1 0.8875443E-02 1.412571 707.9292 48.30930 10.92206 -1.553975 1.884443
5 S 1 0.1081683E-01 1.721551 580.8715 0.7554917E-01 -15.27614 -79.22258 373.0162
6 S 1 0.1244091E-01 1.980032 505.0423 2.538694 5.175243 -11.61870 3.386794
7 S 1 0.1397191E-01 2.223698 449.7014 10.13373 5.729516 -5.166679 6.554098
8 S 1 0.1805191E-01 2.873050 348.0621 6.155373 10.65960 -6.995519 7.559446
9 S 1 0.2008666E-01 3.196891 312.8039 230.4233 0.6267238 -0.4342458E-01 0.3481463
10 S 1 0.2141063E-01 3.407607 293.4611 0.3448219 -38.97194 -34.70601 278.2274
11 S 1 0.2316173E-01 3.686304 271.2744 88.78967 14.10867 -1.670522 16.82045
12 S 1 0.2701024E-01 4.298813 232.6224 236.6933 0.7343129 -0.1703861E-02 3.096444
13 S 1 0.2825395E-01 4.496756 222.3825 574.7770 13.55924 -0.1655211 14.42745
14 S 1 0.3106251E-01 4.943752 202.2755 0.9290075 -25.05111 -20.84662 803.3361
15 S 1 0.3328973E-01 5.298225 188.7424 11.26922 10.80844 -5.017987 29.67733
16 S 1 0.3363177E-01 5.352663 186.8229 186.7498 0.6815058 -0.1118208 5.436482
17 S 1 0.3852959E-01 6.132175 163.0743 17.76272 10.60672 -3.800325 15.07691
18 S 1 0.4022024E-01 6.401250 156.2195 59.85668 0.3067229 -1.482727 12.44268
19 S 1 0.4052649E-01 6.449992 155.0390 1.620413 -22.70559 -15.48013 119.3946
20 S 1 0.4371738E-01 6.957837 143.7228 315.8883 14.76968 -0.2500412 44.18728
21 S 1 0.4708720E-01 7.494161 133.4372 219.2850 0.3131102 -0.5657745E-02 3.307284
22 S 1 0.4916271E-01 7.824488 127.8039 695.2129 14.39722 -0.2159022E-01 21.22786
23 S 1 0.4980496E-01 7.926705 126.1558 1.223670 -27.76285 -17.88477 1822.653
|
可以注意到倒数第二列的wdiff与EPS的量级相差特别大。主要原因在于ifx 和 ifort 在 -O4 表现完全不同,不可替代!
对于ifort而言ifort -O4 = -O3 + 自动搜索最 aggressive 的安全优化; 而对于ifx而言
ifx -O4 = -O3 + LLVM 激进向量化 + aggressive FMA + 重排序优化,
这会导致浮点运算顺序变化、临时数组不同、FMA 异常增多,最后可能导致数值偏差巨大。
(尤其在地震/波动方程/反演中非常明显)
为了保证Mineos计算结果的精确性,这里我们需要重新修改ifx的编译选项,经过测试如果将编译选项修改为如下设置,可以得到正确的结果:
1
| ifx -O1 -c -fp-model strict -fprotect-parens -assume norealloc_lhs -save -132 -zero -o
|
重新编译后,再次运行Mineos,得到的./tmp/PREMQL6ic_21808e_sph_0000001.fre新的输出如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| 1 S 1 0.3221635E-03 0.5127391E-01 19503.10 146937.9 295.9617 -0.3501754E-08 6771.973
2 S 1 0.2538264E-02 0.4039773 2475.387 434.5757 12.24017 0.4125605E-10 5.564181
3 S 1 0.5927811E-02 0.9434405 1059.950 878.4544 5.733120 -0.3097518E-09 3.194875
4 S 1 0.8875441E-02 1.412570 707.9293 399.8989 10.99386 -0.6089271E-10 2.000110
5 S 1 0.1081632E-01 1.721470 580.8987 112.2383 27.03053 0.1045945E-09 515.9343
6 S 1 0.1244083E-01 1.980020 505.0453 711.4472 8.212773 0.9846126E-11 5.688785
7 S 1 0.1397189E-01 2.223695 449.7019 277.5223 6.663123 -0.3257475E-10 8.962321
8 S 1 0.1805188E-01 2.873045 348.0627 1014.246 13.25810 0.3057082E-10 11.18563
9 S 1 0.2008666E-01 3.196891 312.8039 242.5664 0.6311749 -0.7256323E-10 0.4328009
10 S 1 0.2141025E-01 3.407547 293.4662 110.1331 24.30666 0.5006268E-10 344.7550
11 S 1 0.2316173E-01 3.686305 271.2744 742.9176 14.32222 -0.8741872E-10 20.16172
12 S 1 0.2701024E-01 4.298813 232.6224 238.2346 0.7347342 0.3184504E-09 3.236207
13 S 1 0.2825395E-01 4.496756 222.3825 834.1663 13.55285 -0.4994079E-09 15.23383
14 S 1 0.3106237E-01 4.943730 202.2764 108.4183 24.39078 -0.4525127E-10 959.4898
15 S 1 0.3328972E-01 5.298223 188.7425 783.1569 15.60487 0.1933059E-08 41.40665
16 S 1 0.3363177E-01 5.352663 186.8229 209.9107 0.7263867 -0.2194512E-08 7.044347
17 S 1 0.3852958E-01 6.132173 163.0743 849.2041 14.69070 0.3829427E-09 22.69608
18 S 1 0.4022024E-01 6.401249 156.2195 210.8046 1.276628 -0.2982127E-09 14.26391
19 S 1 0.4052641E-01 6.449979 155.0393 107.1371 25.52199 -0.2832593E-09 139.7245
20 S 1 0.4371738E-01 6.957837 143.7228 1008.004 14.96558 -0.1824691E-09 47.50999
21 S 1 0.4708720E-01 7.494161 133.4372 221.1101 0.3165256 0.1452942E-09 3.513345
22 S 1 0.4916271E-01 7.824488 127.8039 928.4059 14.42236 -0.2313127E-09 21.64487
23 S 1 0.4980490E-01 7.926696 126.1560 105.1279 26.39682 -0.1664176E-09 2108.979
|
可以注意到倒数第二列的wdiff与EPS的量级区别不大。
在使用新的intel fortran编译器时编译之前的代码时,一定要对比一下两种编译器在相同编译参数下的表现,尽量选择数值结果接近的ifx的编译选项。
参考资料