新的公开免费使用的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的编译选项。

参考资料

  • ChatGPT