Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/fortran/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Matlab 为什么我的程序返回不准确的结果?_Matlab_Fortran_Subroutine - Fatal编程技术网

Matlab 为什么我的程序返回不准确的结果?

Matlab 为什么我的程序返回不准确的结果?,matlab,fortran,subroutine,Matlab,Fortran,Subroutine,在我最初用MATLAB编写(并优化)这个著名的程序之后,我用Fortran编写了它。将naive转换为Fortran后的加速比至少为18倍,但问题是Fortran程序的输出不准确。正确的输出应该是1.27424153,但是我的Fortran程序输出1.273722712,我在Fortran中做错了什么 program perf_spectralnorm implicit none integer, parameter :: n = 5500, dp = kind(0.d0) real(dp)

在我最初用MATLAB编写(并优化)这个著名的程序之后,我用Fortran编写了它。将naive转换为Fortran后的加速比至少为18倍,但问题是Fortran程序的输出不准确。正确的输出应该是
1.27424153
,但是我的Fortran程序输出
1.273722712
,我在Fortran中做错了什么

program perf_spectralnorm
implicit none
integer, parameter :: n = 5500, dp = kind(0.d0) 
real(dp) :: u(n) = 1, v(n), w(n), vBv, vv, res
integer  :: i, j, nvec(n)

nvec = [(i, i=1,n)]
do i = 1,10
   call Au(w, u)   ! change w
   call Atu(v, w)  ! change v
   call Au(w, v)   ! change w
   call Atu(u, w)  ! change u
end do
vBv = dot_product(u, v) 
vv  = dot_product(v, v)
res = sqrt(vBv/vv)

print '(f12.9)', res

contains 

elemental real(dp) function A(i, j)
   integer, intent(in) :: i, j
   A = 1.0_dp / ((i+j) * (i+j+1.0_dP)/2 + i + 1)
end

subroutine Au(w, u)
   real(dp) :: w(:), u(:)  
   do i = 1,n 
      w(i) = dot_product(A(i-1,nvec-1) , u)  
   end do
end

subroutine Atu(v, w)
   real(dp) :: v(:), w(:)     
   do i = 1,n  
      v(i) = dot_product(A(nvec-1,i-1) , w)       
   end do
end

end program perf_spectralnorm
我在MATLAB中的原始实现,正确的输出如下:

n = 5500; 
fprintf("%.9f\n", perf_spectralnorm(n))

function res = A(i,j) 
    res = 1 ./ ((i+j) .* (i+j+1)/2 + i + 1);
end

function w = Au(u,w)
    n = length(u);
    j = 1:n;
    for i = 1:n         
        w(i) = dot( A(i-1,j-1), u );
    end
end

function v = Atu(w,v)
    n = length(w);
    j = 1:n;
    for i = 1:n         
        v(i) = dot( A(j-1,i-1), w );
    end
end

function res = perf_spectralnorm(n)
    u = ones(n,1);
    v = zeros(n,1);
    w = zeros(n,1);
    for i = 1:10
        w = Au(u,w);
        v = Atu(w,v);
        w = Au(v,w);
        u = Atu(w,u);
    end
    vBv = dot(u,v);
    vv  = dot(v,v);
    res = sqrt(vBv/vv);
end

子程序
Au
Atu
使用变量
i
进行do循环通过主机关联。这修改了主程序中的do循环变量
i
,该变量无效。要解决此问题,需要在
Au
Atu
中将
i
声明为局部变量。比如说,

subroutine Au(w, u)
     real(dp), intent(out) :: w(:)
     real(dp), intent(in)  :: u(:)
     integer i
     do i = 1, n 
        w(i) = dot_product(A(nvec-1,i-1), u)  
     end do
  end

注意,我还冒昧地加入了伪参数的
INTENT

子例程
Au
Atu
为do循环主机关联使用变量
I
。这修改了主程序中的do循环变量
i
,该变量无效。要解决此问题,需要在
Au
Atu
中将
i
声明为局部变量。比如说,

subroutine Au(w, u)
     real(dp), intent(out) :: w(:)
     real(dp), intent(in)  :: u(:)
     integer i
     do i = 1, n 
        w(i) = dot_product(A(nvec-1,i-1), u)  
     end do
  end

请注意,我还冒昧地加入了伪参数的
意图

您使用的是什么Fortran编译器,是否已启用所有调试功能?使用gfortran和-fcheck=all-Wall,我在文件a.f90 Fortran运行时错误:循环变量已被修改”的第8行得到一个运行时错误“是的,子程序Au和Atu通过主机关联使用变量
I
。您需要在这些例程中本地声明
i
。@evets--非常感谢,您是对的,我倾向于在子例程中使用隐式变量(非常坏的习惯)。在我的例子中,主程序中
I
的值将其值传播到被调用的子例程。请写一个答案。你用的是什么Fortran编译器,你打开了所有调试功能了吗?使用gfortran和-fcheck=all-Wall,我在文件a.f90 Fortran运行时错误:循环变量已被修改”的第8行得到一个运行时错误“是的,子程序Au和Atu通过主机关联使用变量
I
。您需要在这些例程中本地声明
i
。@evets--非常感谢,您是对的,我倾向于在子例程中使用隐式变量(非常坏的习惯)。在我的例子中,主程序中
I
的值将其值传播到被调用的子例程。请写一个答案。我做了一些测试,通过设置
nvec
a
参数,与给出的解决方案相比,
gfortran-Ofast
的速度提高了33%。我的i5-1.6GHz不太令人印象深刻,只有3.39秒。通过仅使用数组隐含do构造函数而不是
do
循环和
nvec
可以获得相同的结果。我做了一些测试,通过使用
nvec
a
参数
,与给出的解决方案相比,
gfortran-Ofast
的速度提高了33%。我的i5-1.6GHz不太令人印象深刻,只有3.39秒。通过仅使用数组隐含do构造函数而不是
do
循环和
nvec
可以获得相同的结果。