我有以下MATLAB代码,它执行以下操作。
假设我有10个单位的3个投资。如果退出投资,矩阵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
。有什么方法可以避免这种情况吗?
答案 0 :(得分:2)
这可能是一个扩展的评论而不是答案......
表达式
(pos == 1) * ret(1,1) + (pos == 2) * ret(2,1)
以Fortran无法接受的方式混合类型。第一个词(pos == 1)
的类型为logical
,评估为.true.
或.false.
。这不是一个可以乘以数字或其他任何东西的东西。
实际上,事情比我第一次意识到的要差一些,因为pos
是一个数组。您是否期望得到一系列结果,或者该期限的单个结果?
我不确定您要做什么,但如果您想要将(pos == 1)
转换为数字,则需要将其转换为数字。编写Fortran函数可以很容易地为1
输入返回.true.
(或任何你想要的),并为.false.
输入返回另一个数字。
最后,我很惊讶您的Fortran代码在评论中断言时返回任何内容。我很惊讶它汇编了。
答案 1 :(得分:0)
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并将原始代码中的所有2-D数组更改为1-D数组以简化。
对于其他编译器,上面的代码可能在语法上是不允许的;在这种情况下,定义一些实用程序函数(如
)可能很有用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
形状相同的数组,所以即使对于多维数组也是如此。