我是物理学家,最近我一直在与Fortran合作。最初,我将Java广泛用于娱乐,因为它是我学习的第一门语言,但是我将其放弃用于Fortran和C ++。我对素数充满了业余爱好,因此创建了素数筛子。我能够在15秒内找到所有最高达2 ^ 31的质数。这是Java的最大数组大小,到此为止。我仔细地移植了代码(我是认真的说,我非常沮丧,我的代码太慢了,以至于我找不到错误,因此我将Fortran代码移植回Java以验证这不是我的错,然后将其移植回Java到Fortran,删除每次迭代!)。问题在于,大约有8亿台Fortran会停顿下来。到那时为止,它击败了Java,但之后却变得异常缓慢。我花了几个小时将其绘制并拟合曲线。它以指数的速度降低,可能需要数百年才能解决Java级别的问题。我问过很多人无济于事。为什么这发生在我身上?!?!有什么明智的Fortran编码员可以帮助我吗?我正在运行2013年下半年的Macbook Pro i5。我的代码如下。
program sieve
integer(4),allocatable:: prime(:)
integer(4)::a,max,b,primeCount
write(*,*)"Welcome to the slow prime number sieve!"
write(*,*)"--------------------------------------------"
write(*,*)"Up to what numbers do you need to find primes for?"
write(*,*)"Enter a number below 2^(32-1)"
read*, max
primeCount=0
allocate(prime(max))
prime(1)=1
do a=2,int(sqrt(real(max))) !the main loop
if(prime(a)==0)then !if the number is marked as prime procede
do b=2*a,max,a !eliminate all the numbers that are multiples of the number
if(prime(b)==0)then !but only spend time eliminating if the number is still marked prime
prime(b)=1
end if
end do
end if
end do
do a=1,max
if(prime(a)==0)then
primeCount=primeCount+1
end if
end do
print*, primeCount
end program
编辑:我的机器安装了4 Gig的ram
我可以看到您可以采取几种措施来加快代码的速度,尽管它们似乎都无法解释您所经历的性能急剧下降。罪魁祸首似乎是亚历山大·沃格特(Alexander Vogt)建议的RAM限制。
您应该做的第一件事是将prime
from更改integer
为logical
array。这减少了内存需求,并加快了的评估if (prime(a)==0)
。
代码的相关部分如下所示
logical(1),allocatable:: prime(:)
primeCount=0
allocate(prime(max))
prime = .false.
prime(1)=.true.
do a=2,int(sqrt(real(max))) !the main loop
if(.not. prime(a))then !if the number is marked as prime procede
do b=2*a,max,a !eliminate all the numbers that are multiples of the number
if(.not. prime(b))then !but only spend time eliminating if the number is still marked prime
prime(b)=.true.
end if
end do
end if
end do
do a=1,max
if(.not. prime(a))then
primeCount=primeCount+1
end if
end do
我没有做任何Java编程,但是在Matlab中,如果您声明prime(1:max)=0
然后仅在21之间切换值0
,1
我会认为Matlab将数组视为logical
数组。Java可能也在做同样的事情。这可以解释为什么您的Java代码不会遭受性能下降的影响(假定RAM约束确实是问题所在)。
编辑:我做了一些实验。
在我的机器(Debian Linux 64位,i3、16GB RAM,具有默认标志的ifort 14)上,花了22秒max=800 million (8E8)
。花费了60秒max=2E9
。这不是问题所报告的时间。同样在每种情况下,prime
数组碰巧都初始化为零。
此外,使用integer(1)
可使程序的运行速度比使用快33%integer(4)
。使用时logical(1)
,运行速度比使用时快5%integer(1)
。此行为可能是由于更好地使用现金所致,因为每个现金元素都prime
占用较少的内存空间,因此处理器可以对当前的现金数据更快地循环进行更多次迭代。
我从中得出的结论是,罪魁祸首是亚历山大·沃格特(Alexander Vogt)指出的缺少RAM,并且作者的经验很可能不受初始化prime
数组的遗漏的影响(尽管绝对不应该发生) ),就像HighPerformanceMark指出的那样。此外,我怀疑Java声明prime
为逻辑数组,这就是为什么在那里没有发生问题的原因。(尽管在Java中仅15秒即可获得2 ^ 31的收益?这里使用的Fortran代码与此相距甚远。是否真的比较了相同的代码?)
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句