【发布时间】:2012-01-17 10:39:37
【问题描述】:
最近,我读到了一篇post on Stack Overflow 关于寻找完美平方整数的文章。由于我想玩这个,我写了以下小程序:
PROGRAM PERFECT_SQUARE
IMPLICIT NONE
INTEGER*8 :: N, M, NTOT
LOGICAL :: IS_SQUARE
N=Z'D0B03602181'
WRITE(*,*) IS_SQUARE(N)
NTOT=0
DO N=1,1000000000
IF (IS_SQUARE(N)) THEN
NTOT=NTOT+1
END IF
END DO
WRITE(*,*) NTOT ! should find 31622 squares
END PROGRAM
LOGICAL FUNCTION IS_SQUARE(N)
IMPLICIT NONE
INTEGER*8 :: N, M
! check if negative
IF (N.LT.0) THEN
IS_SQUARE=.FALSE.
RETURN
END IF
! check if ending 4 bits belong to (0,1,4,9)
M=IAND(N,15)
IF (.NOT.(M.EQ.0 .OR. M.EQ.1 .OR. M.EQ.4 .OR. M.EQ.9)) THEN
IS_SQUARE=.FALSE.
RETURN
END IF
! try to find the nearest integer to sqrt(n)
M=DINT(SQRT(DBLE(N)))
IF (M**2.NE.N) THEN
IS_SQUARE=.FALSE.
RETURN
END IF
IS_SQUARE=.TRUE.
RETURN
END FUNCTION
使用gfortran -O2编译时,运行时间为4.437秒,使用-O3为2.657秒。然后我认为使用ifort -O2 编译可能会更快,因为它可能具有更快的SQRT 函数,但结果现在运行时间为9.026 秒,与ifort -O3 相同。我尝试使用 Valgrind 进行分析,Intel 编译的程序确实使用了更多的指令。
我的问题是为什么?有没有办法找出差异的确切来源?
编辑:
- gfortran 4.6.2 版和 ifort 12.0.2 版
- 时间是通过运行
time ./a.out获得的,是实际/用户时间(sys 总是几乎为 0) - 这是在 Linux x86_64 上,gfortran 和 ifort 都是 64 位版本
- ifort 内联所有内容,gfortran 仅在 -O3 处,但后者的汇编代码比 ifort 更简单,ifort 大量使用 xmm 寄存器
- 修复了代码行,在循环之前添加了
NTOT=0,应该可以解决其他 gfortran 版本的问题
当复杂的IF 语句被删除时,gfortran 需要大约 4 倍的时间(10-11 秒)。这是意料之中的,因为该声明大约抛出了大约 75% 的数字,避免对它们执行 SQRT。另一方面,ifort 只使用了稍微多一点的时间。我的猜测是,当 ifort 尝试优化 IF 语句时出现问题。
EDIT2:
我尝试使用 ifort 版本 12.1.2.273,它的速度要快得多,所以看起来他们修复了这个问题。
【问题讨论】:
-
这些是 wall 时间还是 CPU 时间?您可以为每个粘贴
time <program>的输出吗?这些是 32 位版本还是 64 位版本? -
你试过反汇编每个编译器发出的目标文件并比较它们吗?
-
@talonmies:不,我没有,因为我不太了解汇编。虽然运行通过
valgrind --tool=callgrind --dump-instr=yes也给出了汇编代码,但这确实很复杂(很多差异)并且取决于优化级别。 -
您是否尝试过更激进的优化级别?他们可能是值得的。
-
你确定你的程序是正确的吗?使用比 4.5 更新的 gfortran 版本,我得到了不同的答案。
标签: fortran