Algorithm Fortran语言中的大实数运算
我写了一个Fortran代码,计算给定列表Algorithm Fortran语言中的大实数运算,algorithm,visual-studio-2013,fortran,Algorithm,Visual Studio 2013,Fortran,我写了一个Fortran代码,计算给定列表{1,2,3,…,n}的第I个置换,而不计算所有其他的n为了找到TSP(旅行商问题)的第I条路径,我需要它 当n很大,代码给了我一些错误,我测试了发现的第I个置换不是准确的值。对于n=10,根本没有问题,但是对于n=20,会发现代码崩溃或错误值。我认为这是由于Fortran在处理大数(大数之和)时出错造成的 我使用Visual Fortran Ultimate 2013。在附件中,您可以找到我用于我的目标的子程序WeightAdjMatRete是网络中每
{1,2,3,…,n}
的第I个置换,而不计算所有其他的n代码>为了找到TSP(旅行商问题)的第I条路径,我需要它
当n代码>很大,代码给了我一些错误,我测试了发现的第I个置换不是准确的值。对于n=10,根本没有问题,但是对于n=20
,会发现代码崩溃或错误值。我认为这是由于Fortran在处理大数(大数之和)时出错造成的
我使用Visual Fortran Ultimate 2013。在附件中,您可以找到我用于我的目标的子程序WeightAdjMatRete
是网络中每对节点之间的距离矩阵
! Fattoriale
RECURSIVE FUNCTION factorial(n) RESULT(n_factorial)
IMPLICIT NONE
REAL, INTENT(IN) :: n
REAL :: n_factorial
IF(n>0) THEN
n_factorial=n*factorial(n-1)
ELSE
n_factorial=1.
ENDIF
ENDFUNCTION factorial
! ith-permutazione di una lista
SUBROUTINE ith_permutazione(lista_iniziale,n,i,ith_permutation)
IMPLICIT NONE
INTEGER :: k,n
REAL :: j,f
REAL, INTENT(IN) :: i
INTEGER, DIMENSION(1:n), INTENT(IN) :: lista_iniziale
INTEGER, DIMENSION(1:n) :: lista_lavoro
INTEGER, DIMENSION(1:n), INTENT(OUT) :: ith_permutation
lista_lavoro=lista_iniziale
j=i
DO k=1,n
f=factorial(REAL(n-k))
ith_permutation(k)=lista_lavoro(FLOOR(j/f)+1)
lista_lavoro=PACK(lista_lavoro,MASK=lista_lavoro/=ith_permutation(k))
j=MOD(j,f)
ENDDO
ENDSUBROUTINE ith_permutazione
! Funzione modulo, adattata
PURE FUNCTION mood(k,modulo) RESULT(ris)
IMPLICIT NONE
INTEGER, INTENT(IN) :: k,modulo
INTEGER :: ris
IF(MOD(k,modulo)/=0) THEN
ris=MOD(k,modulo)
ELSE
ris=modulo
ENDIF
ENDFUNCTION mood
! Funzione quoziente, adattata
PURE FUNCTION quoziente(a,p) RESULT(ris)
IMPLICIT NONE
INTEGER, INTENT(IN) :: a,p
INTEGER :: ris
IF(MOD(a,p)/=0) THEN
ris=(a/p)+1
ELSE
ris=a/p
ENDIF
ENDFUNCTION quoziente
! Vettori contenenti tutti i payoff percepiti dagli agenti allo state vector attuale e quelli ad ogni sua singola permutazione
SUBROUTINE tuttipayoff(n,m,nodi,nodi_rete,sigma,bvector,MatVecSomma,VecPos,lista_iniziale,ith_permutation,lunghezze_percorso,WeightAdjMatRete,array_perceived_payoff_old,array_perceived_payoff_neg)
IMPLICIT NONE
INTEGER, INTENT(IN) :: n,m,nodi,nodi_rete
INTEGER, DIMENSION(1:nodi), INTENT(IN) :: sigma
INTEGER, DIMENSION(1:nodi), INTENT(OUT) :: bvector
REAL, DIMENSION(1:m,1:n), INTENT(OUT) :: MatVecSomma
REAL, DIMENSION(1:m), INTENT(OUT) :: VecPos
INTEGER, DIMENSION(1:nodi_rete), INTENT(IN) :: lista_iniziale
INTEGER, DIMENSION(1:nodi_rete), INTENT(OUT) :: ith_permutation
REAL, DIMENSION(1:nodi_rete), INTENT(OUT) :: lunghezze_percorso
REAL, DIMENSION(1:nodi_rete,1:nodi_rete), INTENT(IN) :: WeightAdjMatRete
REAL, DIMENSION(1:nodi), INTENT(OUT) :: array_perceived_payoff_old,array_perceived_payoff_neg
INTEGER :: i,j,k
bvector=sigma
FORALL(i=1:nodi,bvector(i)==-1)
bvector(i)=0
ENDFORALL
FORALL(i=1:m,j=1:n)
MatVecSomma(i,j)=bvector(m*(j-1)+i)*(2.**REAL(n-j))
ENDFORALL
FORALL(i=1:m)
VecPos(i)=1.+SUM(MatVecSomma(i,:))
ENDFORALL
DO k=1,nodi
IF(VecPos(mood(k,m))<=factorial(REAL(nodi_rete))) THEN
CALL ith_permutazione(lista_iniziale,nodi_rete,VecPos(mood(k,m))-1.,ith_permutation)
FORALL(i=1:(nodi_rete-1))
lunghezze_percorso(i)=WeightAdjMatRete(ith_permutation(i),ith_permutation(i+1))
ENDFORALL
lunghezze_percorso(nodi_rete)=WeightAdjMatRete(ith_permutation(nodi_rete),ith_permutation(1))
array_perceived_payoff_old(k)=(1./SUM(lunghezze_percorso))
ELSE
array_perceived_payoff_old(k)=0.
ENDIF
IF(VecPos(mood(k,m))-SIGN(1,sigma(m*(quoziente(k,m)-1)+mood(k,m)))*2**(n-quoziente(k,m))<=factorial(REAL(nodi_rete))) THEN
CALL ith_permutazione(lista_iniziale,nodi_rete,VecPos(mood(k,m))-SIGN(1,sigma(m*(quoziente(k,m)-1)+mood(k,m)))*2**(n-quoziente(k,m))-1.,ith_permutation)
FORALL(i=1:(nodi_rete-1))
lunghezze_percorso(i)=WeightAdjMatRete(ith_permutation(i),ith_permutation(i+1))
ENDFORALL
lunghezze_percorso(nodi_rete)=WeightAdjMatRete(ith_permutation(nodi_rete),ith_permutation(1))
array_perceived_payoff_neg(k)=(1./SUM(lunghezze_percorso))
ELSE
array_perceived_payoff_neg(k)=0.
ENDIF
ENDDO
ENDSUBROUTINE tuttipayoff
!肥胖症
递归函数阶乘(n)结果(n_阶乘)
隐式无
真实的,意图(IN)::n
实::n_阶乘
如果(n>0),则
n_阶乘=n*阶乘(n-1)
其他的
n_阶乘=1。
恩迪夫
端函数阶乘
! 这是一个很好的选择
子例程ith_置换(列表化,n,i,ith_置换)
隐式无
整数::k,n
实数:j,f
真实的,意图的:i
整数,维度(1:n),意图(IN)::列表
整数,维数(1:n)::lista_lavoro
整数,维数(1:n),意图(OUT)::第i个置换
lista_lavoro=lista_Nizialie
j=i
DO k=1,n
f=阶乘(实(n-k))
第i个置换(k)=lista_lavoro(楼层(j/f)+1)
lista_lavoro=PACK(lista_lavoro,MASK=lista_lavoro/=ith_置换(k))
j=模(j,f)
恩多
ENDSUBROUTINE ith_置换
! Funzione模,adattata
纯函数(k,模)结果(ris)
隐式无
整数,意图(IN)::k,模
整数::ris
如果(MOD(k,模)/=0),那么
ris=模(k,模)
其他的
ris=模
恩迪夫
终功能语气
! 阿达塔库齐恩福锡安酒店
纯函数量子化(a,p)结果(ris)
隐式无
整数,意图(IN)::a,p
整数::ris
如果(MOD(a,p)/=0),则
ris=(应付)+1
其他的
ris=应付账款
恩迪夫
端函数量子化
! 在一个新的变化过程中,所有的变化状态向量都是变化的
子例程tuttipayoff(n,m,nodi,nodi,rete,sigma,bvector,MatVecSomma,VecPos,lista_-inizale,ith_置换,lunghezze_-percorso,WeightAdjMatRete,array_-sensived_-payoff_-old,array_-sensived_-payoff_-neg)
隐式无
整数,意图(IN)::n,m,nodi,nodi_-rete
整数,维度(1:nodi),意图(IN)::西格玛
整数,维度(1:nodi),意图(OUT)::bvector
实,维(1:m,1:n),意图(OUT)::MatVecSomma
真实,尺寸(1:m),意图(外)::VecPos
整数,维度(1:nodi\u rete),意图(IN)::列表
整数,维(1:nodi\u rete),意图(OUT)::第i个置换
真实,维度(1:nodi_rete),意图(OUT)::lunghezze_percorso
实数,维度(1:nodi_-rete,1:nodi_-rete),意图(IN)::WeightAdjMatRete
真实,维度(1:nodi),意图(OUT)::数组\感知\支付\旧,数组\感知\支付\负
整数::i,j,k
bvector=sigma
FORALL(i=1:nodi,bvector(i)=-1)
b向量(i)=0
端孔
FORALL(i=1:m,j=1:n)
MatVecSomma(i,j)=bvector(m*(j-1)+i)*(2**实(n-j))
端孔
所有(i=1:m)
VecPos(i)=1.+和(MatVecSomma(i,:)
端孔
Dok=1,nodi
IF(VecPos(mood(k,m))不要使用浮点数来表示阶乘;阶乘是整数的乘积,因此最好用整数表示
阶乘增长很快,因此使用实数可能很有诱惑力,因为实数可以表示像1.0e+30这样的巨大数字。但浮点数的精确性仅与它们的大小有关;它们的尾数仍然有一个有限的大小,它们可以很大,因为它们的指数可能很大
一个32位实数可以表示高达1600万的精确整数。此后,只有每个偶数整数可以表示高达3200万,每四个整数可以表示高达6400万。64位整数更好,因为它们可以表示高达9万亿的精确整数
64位整数可以再前进1024倍:它们可以表示2^63或大约9个五分之一(9e+18)的整数。这足以表示20!:
20! = 2,432,902,008,176,640,000
2^63 = 9,223,372,036,854,775,808
Fortran允许您根据小数位数选择一种整数:
integer, (kind=selected_int_kind(18))
使用此选项可以对64位整数进行计算。这将为您提供高达20%的阶乘。不过,它不会超出此范围:大多数计算机只支持高达64位的整数,因此selected\u int\u kind(19)
将给您一个错误
这是程序中64位整数的置换部分。请注意所有类型转换ald地板和天花板是如何消失的
program permute
implicit none
integer, parameter :: long = selected_int_kind(18)
integer, parameter :: n = 20
integer, dimension(1:n) :: orig
integer, dimension(1:n) :: perm
integer(kind=long) :: k
do k = 1, n
orig(k) = k
end do
do k = 0, 2000000000000000_long, 100000000000000_long
call ith_perm(perm, orig, n, k)
print *, k
print *, perm
print *
end do
end program
function fact(n)
implicit none
integer, parameter :: long = selected_int_kind(18)
integer(kind=long) :: fact
integer, intent(in) :: n
integer :: i
fact = 1
i = n
do while (i > 1)
fact = fact * i
i = i - 1
end do
end function fact
subroutine ith_perm(perm, orig, n, i)
implicit none
integer, parameter :: long = selected_int_kind(18)
integer, intent(in) :: n
integer(kind=long), intent(in) :: i
integer, dimension(1:n), intent(in) :: orig
integer, dimension(1:n), intent(out) :: perm
integer, dimension(1:n) :: work
integer :: k
integer(kind=long) :: f, j
integer(kind=long) :: fact
work = orig
j = i
do k = 1, n
f = fact(n - k)
perm(k) = work(j / f + 1)
work = pack(work, work /= perm(k))
j = mod(j, f)
end do
end subroutine ith_perm
您是否尝试在代码中对浮点变量使用双精度?首先尝试较大的整数和实数类型是的,我对实数使用双精度,因为实数允许范围很广的数字,而不是整数。@IlarioDeVincenzo在代码中,您使用的是单精度浮点数(real::…
)。要切换到双精度,您需要指定相应的kind
,例如real(kind=kind(1.d0))::…
双精度不仅扩展范围(指数),还扩展精度(尾数)@IlarioDeVincenzo:是的,但是大实数可能没有将阶乘存储为整数所需的精度。单精度可以表示高达1600万左右的所有整数;双精度可以表示高达9千万(9·10^16)左右的所有整数。阶乘不是实数;使用整数。非常感谢您的回答。我发现运行您编写的代码时只有一个问题。在我的算法迭代的某个时刻,代码中断,因为j/f+1变得比“work”的大小更大。这是怎么可能的?只有当i
等于或大于n!时才会发生这种情况。您的索引i
是基于零的。您可以通过首先使i=mod(i,n!)
来捕捉这种情况,但它更可能是一个计算错误的inpu