首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >怎么用Fortran写这个?

怎么用Fortran写这个?
EN

Stack Overflow用户
提问于 2016-05-11 13:33:10
回答 2查看 147关注 0票数 1

我有下面的MATLAB代码,它做以下工作。

假设我有3个10个单元的投资。如果投资退出,矩阵exits的值为1。矩阵pos告诉我这三项投资中每一项的回报。然后,代码的最后一行计算退出投资的总收益。

我正试图用Fortran编写类似的代码行。也低于我的Fortran尝试。

代码语言:javascript
复制
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密码:

代码语言:javascript
复制
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,我还必须创建两个额外的变量。有办法避免这种情况吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-05-11 16:53:20

Matlab中的pos == 1返回由1和0组成的数组,而返回由Fortran中的.true..false.组成的数组(如@HighPerformanceMark所建议的)。所以,你需要以某种方式解决这个差异。这方面有多种方法,其中一个例子是:

代码语言:javascript
复制
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,并将原始代码中的所有二维数组更改为一维数组。

对于其他编译器,上述代码在语法上可能是不允许的;在这种情况下,定义如下的实用程序函数可能是有用的。

代码语言:javascript
复制
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

并将原始代码修改为

代码语言:javascript
复制
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)。使用此函数,可以将第一和第二代码重写为

代码语言:javascript
复制
vtmp = merge( ret(1), 0.0, pos == 1 ) + merge( ret(2), 0.0, pos == 2 )

代码语言:javascript
复制
ret1 = merge( ret(1,1), 0.0, pos == 1 ) + merge( ret(2,1), 0.0, pos == 2 )

因为merge()返回一个与pos形状相同的数组,所以即使在多维数组中使用也是非常直接的。

票数 0
EN

Stack Overflow用户

发布于 2016-05-11 14:25:52

这可能是一个延伸的评论,而不是回答.

表达式

代码语言:javascript
复制
(pos == 1) * ret(1,1) + (pos == 2) * ret(2,1)

以Fortran无法接受的方式混合类型。第一个项,(pos == 1)类型为logical,计算结果为.true..false.。这不是什么东西,然后可以乘以一个数字,或任何其他的事情。

实际上,事情比我第一次意识到的还要糟糕,因为pos是一个数组。您希望得到一系列的结果,还是该术语中的单个结果?

我不知道你想要做什么,但是如果你想把(pos == 1)乘以它,你就需要把它转换成一个数字。很容易编写一个Fortran函数来为一个1输入返回.true. (或您想要的任何东西),而为一个.false.输入返回另一个数字。

最后,当您在评论中断言时,您的Fortran代码会返回任何内容,这让我感到惊讶。我很惊讶它会编译。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37164280

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档