Fortran 为什么这个代码给了我不正确的答案?
我正在尝试编写一个程序,使用lcg作为函数,使用box-muller算法计算更多的随机数。我已经让lcg工作,但是使用box-muller算法的函数给出了错误的值 这是我的密码:Fortran 为什么这个代码给了我不正确的答案?,fortran,gfortran,fortran90,Fortran,Gfortran,Fortran90,我正在尝试编写一个程序,使用lcg作为函数,使用box-muller算法计算更多的随机数。我已经让lcg工作,但是使用box-muller算法的函数给出了错误的值 这是我的密码: module rng implicit none integer, parameter :: dp = selected_real_kind(15,300) real(kind=dp) :: A=100, B= 104001, M = 714025 contains function lcg(seed
module rng
implicit none
integer, parameter :: dp = selected_real_kind(15,300)
real(kind=dp) :: A=100, B= 104001, M = 714025
contains
function lcg(seed)
integer, optional, intent(in) :: seed
real(kind=dp) :: x = 0, lcg
if(present(seed)) x = seed
x = mod(A * x + B, M)
lcg = x/714025
end function
function muller(seed)
integer, parameter :: dp = selected_real_kind(15,300)
integer, optional, intent(in) :: seed
real(kind = dp) :: y1, y2, mean = 0.49, sd = 0.5, muller1, muller2,
muller, x1, x2, pi = 4.0*ATAN(1.0)
integer :: N = 0
! I had to add the do while loop to ensure that this chunk of code would
only execute once
do while (N<1)
x1 = lcg()
x2 = lcg()
N = N + 1
y1 = sd * SQRT(-2.0*LOG(x1)) * COS(2*pi*(x2)) + mean
y2 = sd * SQRT(-2.0*LOG(x1)) * SIN(2*pi*(x2)) + mean
print *, y1, y2, x1, x2 ! Printing x1 and x2 to allow me to use a
calculator to check program is working correctly
end do
end function
end module
program lcgtest
use rng
implicit none
integer :: N
real(kind=dp) :: lcgmean, ttl = 0, sumof, lcgvar, dev1, muller1, muller2,
lcgerr, lcgdev
real, dimension(10000) :: array
do N = 1, 10000
ttl = ttl + lcg()
dev1 = lcg() - lcgmean
sumof = sumof + dev1
end do
muller1 = muller()
muller2 = muller()
lcgmean = ttl/10000
lcgvar = ((sumof)**2)/10000
lcgdev = SQRT((sumof)**2)/10000
lcgerr = lcgdev/100
print *, lcg(), "mean=", lcgmean, "variance=", lcgvar, lcgerr
end program
模块rng
隐式无
整数,参数::dp=所选的实数种类(15300)
实数(种类=dp)::A=100,B=104001,M=714025
包含
功能lcg(种子)
整数,可选,意图(in)::种子
实际(种类=dp)::x=0,lcg
如果(存在(种子))x=种子
x=mod(A*x+B,M)
lcg=x/714025
端函数
功能研磨机(种子)
整数,参数::dp=所选的实数种类(15300)
整数,可选,意图(in)::种子
实际(种类=dp):y1,y2,平均值=0.49,标准差=0.5,穆勒尔1,穆勒尔2,
穆勒,x1,x2,pi=4.0*ATAN(1.0)
整数::N=0
! 我必须添加do-while循环,以确保这段代码
只执行一次
我不知道你对这个程序的预期结果是什么。但是,阅读它,我可以很容易地得到你遵循的逻辑。我注意到两个事实错误。请通读下面的代码以查看我的增强功能
module rng
implicit none
integer, parameter :: dp = selected_real_kind(15,300)
real(kind=dp) :: A=100, B= 104001, M = 714025
contains
function lcg(seed)
integer, optional, intent(in) :: seed
real(kind=dp) :: x = 0, lcg
if(present(seed)) x = seed
x = mod(A * x + B, M)
lcg = x/714025
end function lcg ! Note 'lcg' here @ the end
function muller(seed)
integer, parameter :: dp = selected_real_kind(15,300)
integer, optional, intent(in) :: seed
real(kind = dp) :: y1, y2, mean = 0.49, sd = 0.5, muller1, &
muller2, muller, x1, x2, pi = 4.0*ATAN(1.0)
integer :: N = 0
! I had to add the do while loop to ensure that this chunk
! of code would only execute once
do while (N<1)
x1 = lcg()
x2 = lcg()
N = N + 1
y1 = sd * SQRT(-2.0*LOG(x1)) * COS(2*pi*(x2)) + mean
y2 = sd * SQRT(-2.0*LOG(x1)) * SIN(2*pi*(x2)) + mean
! Printing x1 and x2 to allow me to use a
! calculator to check program is working correctly
print *, y1, y2, x1, x2
enddo
end function muller ! note the function name @ the end here
end module rng ! Note 'rng' here added.
program lcgtest
use rng
implicit none
integer :: N
real(kind=dp) :: lcgmean, ttl = 0, sumof, lcgvar, dev1, muller1, &
muller2, lcgerr, lcgdev
real, dimension(10000) :: array
! In the original code the variables 'lcgmean' and 'dev1' were
! *undefined* before they were used in the do-loop. This will cause the
! compiler to set them some random garbage values, and it will
! inevitably leads to unexpected result or error in most cases.
! In, order to avoid this by setting them.
! For example, lcgmean = 1.0 and dev1 = 0.1
! We'll then have the following:
lcgmean = 1.0
dev1 = 0.1
do N = 1, 10000
ttl = ttl + lcg()
dev1 = lcg() - lcgmean
sumof = sumof + dev1
end do
muller1 = muller()
muller2 = muller()
lcgmean = ttl/10000
lcgvar = ((sumof)**2)/10000
lcgdev = SQRT((sumof)**2)/10000
lcgerr = lcgdev/100
print *, lcg(), "mean=", lcgmean, "variance=", lcgvar, lcgerr
end program
备注:变量seed
在函数muller
中未使用。可能不需要它。根据我的阅读,似乎最好用子例程替换函数muller,这样它可以同时计算y1和y2。事实上,“块”*muller“目的是根据您的程序结构,基于先前生成的两个伪随机数x1和x2生成另外两个伪随机数
然后,在主程序中,不应将muller作为函数调用,而应通过在相应位置写入call muller将其作为子例程调用。但是,仍然可以使用函数而不是子例程,但要返回两个值y1和y2,您可以rn是向量v,使得v(1)=y1;v(2)=y2
原始程序将变为以下内容:
module rng
implicit none
integer, parameter :: dp = selected_real_kind(15,300)
real(kind=dp) :: A=100, B= 104001, M = 714025
contains
function lcg(seed)
implicit none
integer, optional, intent(in) :: seed
real(kind=dp) :: x = 0, lcg
if(present(seed)) x = seed
x = mod(A * x + B, M)
lcg = x/714025
end function lcg ! Note 'lcg' here @ the end
!-------------------------------------------------------------------
! Subroutine muller.
! Here, we supply 4 arguments *y1, y2* and the optional
! argaument *seed* which apparently is not required since it is not
! used (but can be used in order to have a better pseudo number
! generator.
!-------------------------------------------------------------------
subroutine muller(y1, y2, seed)
implicit none
real(kind=dp), intent(out) :: y1, y2
integer, optional, intent(in) :: seed
! Local variables
real(kind=dp) :: x1, x2
real(kind=dp) :: mean = 0.49, sd = 0.5
real(kind=dp) :: pi = 4.0*ATAN(1.0)
integer :: N = 0
! The **do while** loop is not needed
! do while (N<1)
x1 = lcg()
x2 = lcg()
N = N + 1
y1 = sd * SQRT(-2.0*LOG(x1)) * COS(2*pi*(x2)) + mean
y2 = sd * SQRT(-2.0*LOG(x1)) * SIN(2*pi*(x2)) + mean
! display to the screen the values of x1, x2, y1, y2
print *, y1, y2, x1, x2
! enddo
end subroutine muller
end module rng
program lcgtest
use rng
implicit none
integer :: N
real(kind=dp) :: lcgmean, ttl = 0, sumof, lcgvar, dev1
real(kind=dp) :: lcgerr, lcgdev
! Because the variable **array** is not used, I will comment it out
!real, dimension(10000) :: array
real(kind=dp) :: out_lcg
! In the original code the variables 'lcgmean' and 'dev1' were
! *undefined* before they were used in the do-loop. This will cause the
! compiler to set them some random garbage values, and it will
! inevitably leads to unexpected result or error in most cases.
! In, order to avoid this by setting them.
! For example, lcgmean = 1.0 and dev1 = 0.1
! We'll then have the following:
lcgmean = 1.0
dev1 = 0.1
! The above is true for the variables **sumof**
sumof = 0.0
do N = 1, 10000
ttl = ttl + lcg()
dev1 = lcg() - lcgmean
sumof = sumof + dev1
enddo
call muller(y1, y2)
call muller(y1, y2)
lcgmean = ttl/10000
lcgvar = ((sumof)**2)/10000
lcgdev = SQRT((sumof)**2)/10000
lcgerr = lcgdev/100
out_lcg = lcg()
print *, out_lcg, "mean=", lcgmean, "variance=", lcgvar, lcgerr
end program
模块rng
隐式无
整数,参数::dp=所选的实数种类(15300)
实数(种类=dp)::A=100,B=104001,M=714025
包含
功能lcg(种子)
隐式无
整数,可选,意图(in)::种子
实际(种类=dp)::x=0,lcg
如果(存在(种子))x=种子
x=mod(A*x+B,M)
lcg=x/714025
结束函数lcg!在结束处注意“lcg”
!-------------------------------------------------------------------
!子程序穆勒。
!在这里,我们提供4个参数*y1、y2*和可选参数
!argaument*seed*显然不需要,因为它不是
!used(但可用于获得更好的伪编号
!发电机。
!-------------------------------------------------------------------
子程序研磨器(y1,y2,种子)
隐式无
真实(种类=dp),意图(输出):y1,y2
整数,可选,意图(in)::种子
!局部变量
实际(种类=dp)::x1,x2
实际值(种类=dp):平均值=0.49,标准差=0.5
实数(种类=dp)::pi=4.0*ATAN(1.0)
整数::N=0
!不需要**执行时**循环
快点(请阅读。它给出了哪个答案?你希望得到哪个答案?为什么?y1
和y2
是局部变量,你不给函数结果赋值。这是一个答案,但我不确定它是否有用:你似乎对函数如何工作缺少很多基本的理解。你能提出一个更简单的问题吗urious,为什么不在模块级别执行double(kind=dp),parameter::pi=4.0*ATAN(1.0)
,这样就不会每次都重新计算它?@ja72它不是每次都重新计算,它是一个保存的变量。a(可能是全局的)常量会更好…请注意,这仍然是无效代码:函数结果在函数执行期间未定义muller
。如果OP在正确使用函数方面确实存在问题,则问题相当大。感谢@fracescalus的观点。我将在下面的回答中提供一个备选方案@至少需要注意的是,这个函数不返回任何内容,应该在这个答案中进行编辑,否则它是非常不完整的。@Vladimir F。请看下面我新改进的代码,我想我已经解决了这个问题。
module rng
implicit none
integer, parameter :: dp = selected_real_kind(15,300)
real(kind=dp) :: A=100, B= 104001, M = 714025
contains
function lcg(seed)
implicit none
integer, optional, intent(in) :: seed
real(kind=dp) :: x = 0, lcg
if(present(seed)) x = seed
x = mod(A * x + B, M)
lcg = x/714025
end function lcg ! Note 'lcg' here @ the end
!-------------------------------------------------------------------
! Subroutine muller.
! Here, we supply 4 arguments *y1, y2* and the optional
! argaument *seed* which apparently is not required since it is not
! used (but can be used in order to have a better pseudo number
! generator.
!-------------------------------------------------------------------
subroutine muller(y1, y2, seed)
implicit none
real(kind=dp), intent(out) :: y1, y2
integer, optional, intent(in) :: seed
! Local variables
real(kind=dp) :: x1, x2
real(kind=dp) :: mean = 0.49, sd = 0.5
real(kind=dp) :: pi = 4.0*ATAN(1.0)
integer :: N = 0
! The **do while** loop is not needed
! do while (N<1)
x1 = lcg()
x2 = lcg()
N = N + 1
y1 = sd * SQRT(-2.0*LOG(x1)) * COS(2*pi*(x2)) + mean
y2 = sd * SQRT(-2.0*LOG(x1)) * SIN(2*pi*(x2)) + mean
! display to the screen the values of x1, x2, y1, y2
print *, y1, y2, x1, x2
! enddo
end subroutine muller
end module rng
program lcgtest
use rng
implicit none
integer :: N
real(kind=dp) :: lcgmean, ttl = 0, sumof, lcgvar, dev1
real(kind=dp) :: lcgerr, lcgdev
! Because the variable **array** is not used, I will comment it out
!real, dimension(10000) :: array
real(kind=dp) :: out_lcg
! In the original code the variables 'lcgmean' and 'dev1' were
! *undefined* before they were used in the do-loop. This will cause the
! compiler to set them some random garbage values, and it will
! inevitably leads to unexpected result or error in most cases.
! In, order to avoid this by setting them.
! For example, lcgmean = 1.0 and dev1 = 0.1
! We'll then have the following:
lcgmean = 1.0
dev1 = 0.1
! The above is true for the variables **sumof**
sumof = 0.0
do N = 1, 10000
ttl = ttl + lcg()
dev1 = lcg() - lcgmean
sumof = sumof + dev1
enddo
call muller(y1, y2)
call muller(y1, y2)
lcgmean = ttl/10000
lcgvar = ((sumof)**2)/10000
lcgdev = SQRT((sumof)**2)/10000
lcgerr = lcgdev/100
out_lcg = lcg()
print *, out_lcg, "mean=", lcgmean, "variance=", lcgvar, lcgerr
end program