我有下面的MATLAB代码,它做以下工作。
假设我有3个10个单元的投资。如果投资退出,矩阵exits的值为1。矩阵pos告诉我这三项投资中每一项的回报。然后,代码的最后一行计算退出投资的总收益。
我正试图用Fortran编写类似的代码行。也低于我的Fortran尝试。
clear all
X = 10;
ret(1,1) = -0.05;
ret(2,1) = 0.15;
exits = [1 0 1];
pos = [1 1 2];
ret1 = (pos == 1) .* ret(1,1) + (pos == 2) .* ret(2,1);
inv = sum(X * ones(1,3) .* (exits) .* exp(ret1));我的Fortran密码:
PROGRAM Matlab_replication
IMPLICIT NONE
INTEGER, DIMENSION(1,1) :: X = 10
REAL, DIMENSION(2,1) :: ret
INTEGER, DIMENSION(1,3) :: exits
INTEGER, DIMENSION(1,3) :: pos
REAL, DIMENSION(1,3) :: ret1
REAL, DIMENSION(1,3) :: ret2
REAL, DIMENSION(1,3) :: ones = 1.0
REAL, DIMENSION(1,3) :: X1
REAL :: inv
ret(1,1) = -0.05
ret(2,1) = 0.15
exits(1,1) = 1
exits(1,2) = 0
exits(1,3) = 1
pos(1,1) = 1
pos(1,2) = 1
pos(1,3) = 2
X1(1,:) = X(1,1) * ones(1,:)
ret1 = (pos == 1) * ret(1,1) + (pos == 2) * ret(2,1)
ret2(1,:) = exp(ret1(1,:))
inv = sum(X1(1,:) * exits(1,:)* ret2(1,:))
end program不知何故,ret1 = (pos == 1) * ret(1,1) + (pos == 2) * ret(2,1)没有提供我想要的东西。另外,相对于MATLAB代码X1和ret2,我还必须创建两个额外的变量。有办法避免这种情况吗?
发布于 2016-05-11 16:53:20
Matlab中的pos == 1返回由1和0组成的数组,而返回由Fortran中的.true.和.false.组成的数组(如@HighPerformanceMark所建议的)。所以,你需要以某种方式解决这个差异。这方面有多种方法,其中一个例子是:
real :: ret( 2 ), vtmp( 3 ), inv, x
integer :: exits( 3 ), pos( 3 )
x = 10.0
ret = [ -0.05, 0.15 ]
exits = [ 1, 0, 1 ]
pos = [ 1, 1, 2 ]
vtmp = abs([ integer:: pos == 1 ]) * ret( 1 ) + abs([ integer:: pos == 2 ]) * ret( 2 )
inv = sum( x * exits * exp( vtmp ) )为了简单起见,我假设了gfortran或Intel fortran,并将原始代码中的所有二维数组更改为一维数组。
对于其他编译器,上述代码在语法上可能是不允许的;在这种情况下,定义如下的实用程序函数可能是有用的。
module filter_mod
implicit none
interface filter
module procedure filter1D, filter2D
end interface
contains
function filter1D( mask ) result( ints )
logical :: mask(:)
integer :: ints( size( mask ) )
ints = 0 ; where( mask ) ints = 1
end function
function filter2D( mask ) result( ints )
logical :: mask(:,:)
integer :: ints( size( mask, 1 ), size( mask, 2 ) )
ints = 0 ; where( mask ) ints = 1
end function
end module并将原始代码修改为
PROGRAM Matlab_replication
use filter_mod
IMPLICIT NONE
...
ret1 = filter( pos == 1 ) * ret(1,1) + filter( pos == 2 ) * ret(2,1)
inv = sum( X(1,1) * exits * exp( ret1 ) )希望能把Matlab的翻译变得笔直。
编辑:实际上,使用merge()函数似乎是最简单的解决方案(多亏了@francescalus)。使用此函数,可以将第一和第二代码重写为
vtmp = merge( ret(1), 0.0, pos == 1 ) + merge( ret(2), 0.0, pos == 2 )和
ret1 = merge( ret(1,1), 0.0, pos == 1 ) + merge( ret(2,1), 0.0, pos == 2 )因为merge()返回一个与pos形状相同的数组,所以即使在多维数组中使用也是非常直接的。
发布于 2016-05-11 14:25:52
这可能是一个延伸的评论,而不是回答.
表达式
(pos == 1) * ret(1,1) + (pos == 2) * ret(2,1)以Fortran无法接受的方式混合类型。第一个项,(pos == 1)类型为logical,计算结果为.true.或.false.。这不是什么东西,然后可以乘以一个数字,或任何其他的事情。
实际上,事情比我第一次意识到的还要糟糕,因为pos是一个数组。您希望得到一系列的结果,还是该术语中的单个结果?
我不知道你想要做什么,但是如果你想把(pos == 1)乘以它,你就需要把它转换成一个数字。很容易编写一个Fortran函数来为一个1输入返回.true. (或您想要的任何东西),而为一个.false.输入返回另一个数字。
最后,当您在评论中断言时,您的Fortran代码会返回任何内容,这让我感到惊讶。我很惊讶它会编译。
https://stackoverflow.com/questions/37164280
复制相似问题