如何在Fortran中写这个?

时间:2016-05-11 13:33:10

标签: matlab syntax fortran

我有以下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代码X1ret2。有什么方法可以避免这种情况吗?

2 个答案:

答案 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)

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并将原始代码中的所有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形状相同的数组,所以即使对于多维数组也是如此。