本文介绍了I / O中的数值表达式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找一种方法来读取Fortran中的数字表达式。

数值表达式的意思是 dsqrt(0.5d0)/3.d0+1.d0 翻译后的 1.235 ... 真实版。



阅读我的意思是

open(unit = UnitNumber,file =FileName)
read(UnitNumber,*)....



我尝试在读语句中定义格式,例如 read(unitNumber,(15F24.17)),但它没有帮助。我是



我在想,如果我只能在内部完成,定义 real(8),parameter :: dsqrt(0.5d0)/ 3 .d0 + 1.d0

也许使用 FORMAT 语法可以提供帮助吗?



  module util 
use iso_fortran_env,only:dp => real64
隐式无
包含

子程序eval(expr,ans,x,y)
字符(*),intent(in):: expr
真实(dp),intent(out):: ans
real(dp),intent(in),可选项:: x,y
character(len(expr)+200)cmd,sx, sy
整数u

sx =;如果(present(y))write(sx,('x'',es25.15,';'))x
if sy,('y =',es25.15,';'))y

write(cmd,(a))&
python -cfrom __future__ import print_function,division;//&
from math import *;// trim(sx)// trim(sy)//&
print(eval('// trim(expr)//'))> tmp.dat

call system(trim(cmd))

打开(newunit = u,file =tmp.dat,status =old)
阅读(u,*)ans
关闭(u)

调用系统(rm -f tmp.dat)
结束子程序

结束模块

程序主体
使用util,仅:dp ,eval
implicit none
character(200)str
real(dp)ans

str =sqrt(2.0)+ 1000.0
call eval (str,ans)
print *,ans =,ans

str =acos(x)+ 2000.0
call eval(str,ans,x = - 1.0_dp)
print *,ans =,ans

str =10 * x + y
call eval(str,ans,x = 1.0_dp,y = 2.0_dp)
print *,ans =,ans
end program

结果:

  $ gfortran test.f90#gfortran> = 5推荐
$ ./a。 out
ans = 1001.4142135623731
ans = 200 3.1415926535899
ans = 12.000000000000000






,上面的代码通过system()在Python中调用内置的eval()函数。但是效率不高,因为结果值曾经写入到外部文件中(也是调用Python本身的开销)。所以如果效率很重要,最好使用更具体的第三方库,或者为了方便,直接使用解释型语言。 (如果计算过程不太苛刻,我建议采用后一种方法,因为它为编码节省了大量时间......)

Python:

  from __future__导入print_function,除法
从数学导入*
str = input(输入表达式:)
x = 1.0
y = 2.0
print(eval(str))#如果在提示符中键入x + 10 * y,则会得到21

Julia:

  println(输入表达式:) 
str = readline()
x = 1.0
y = 2.0
println(eval(parse(str)))



$ b

如果可以使用 system()并编写外部文件,另一个选项可能只需编写一个包含要评估表达式的小型Fortran代码,通过system()编译并运行它,通过外部文件得到结果。例如,如果我们替换上面代码中的两行( write(cmd,(a))... system(trim (cmd))),它给出了相同的结果。这可能是有用的,如果我们想保持代码完全写在Fortran,用最小的修改努力。

  open(newunit = u,tmp.f90)
write(u,(a))implicit none
write(u,(a))real :: x,y
write(u,(a))trim(sx)
write(u,(a))trim(sy)
write(u,(a)) (*,'(e30.20)')// trim(expr)
write(u,(a))end
close(u)

呼叫系统(gfortran -fdefault-real-8 -ffree-line-length-none tmp.f90&& ./a.out> tmp.dat)
!假设在Linux或Mac上使用bash(x86_64)。
! -fdefault-real-8被附加到8位浮点值来提升1.0等。

呼叫系统(rm -f tmp.f90)


I am looking for a way to read numerical expressions in Fortran.

With numerical expression I mean dsqrt(0.5d0)/3.d0+1.d0 or something rather then the translated 1.235... real version.

With reading I mean

open(unit=UnitNumber,file="FileName")read(UnitNumber, *) ....

I try to define in the reading statement the format, for instanceread(unitNumber,"(15F24.17)") but it does not help. I am

I am wondering if I can do it only internally, defining real(8), parameter :: dsqrt(0.5d0)/3.d0+1.d0 .

Maybe the use of FORMAT syntax could help?

解决方案

As suggested by @agentp, interpreted languages like Python and Julia can parse a string directly as a piece of code, so utilizing such a feature may be convenient for your purpose. But if you definitely need to achieve the same goal in Fortran, another approach (with least effort!) may be simply to call eval() in such languages, for example:

module util
    use iso_fortran_env, only: dp => real64
    implicit none
contains

subroutine eval( expr, ans, x, y )
    character(*), intent(in)       :: expr
    real(dp), intent(out)          :: ans
    real(dp), intent(in), optional :: x, y
    character(len(expr)+200) cmd, sx, sy
    integer u

    sx = "" ; sy = ""
    if ( present(x) ) write( sx, "(' x = ', es25.15, ' ; ')" ) x
    if ( present(y) ) write( sy, "(' y = ', es25.15, ' ; ')" ) y

    write( cmd, "(a)" ) &
            "python -c ""from __future__ import print_function, division ; " // &
            "from math import * ; " // trim(sx) // trim(sy) // &
            "print( eval( '" // trim(expr) // "' ))"" > tmp.dat"

    call system( trim( cmd ) )

    open( newunit=u, file="tmp.dat", status="old" )
    read( u, * ) ans
    close( u )

    call system( "rm -f tmp.dat" )
end subroutine

end module

program main
    use util, only: dp, eval
    implicit none
    character(200) str
    real(dp) ans

    str = "sqrt( 2.0 ) + 1000.0"
    call eval( str, ans )
    print *, "ans = ", ans

    str = "acos( x ) + 2000.0"
    call eval( str, ans, x= -1.0_dp )
    print *, "ans = ", ans

    str = "10 * x + y"
    call eval( str, ans, x= 1.0_dp, y= 2.0_dp )
    print *, "ans = ", ans
end program

Results:

$ gfortran test.f90    # gfortran >=5 is recommended
$ ./a.out
 ans =    1001.4142135623731
 ans =    2003.1415926535899
 ans =    12.000000000000000


More specifically, the above code simply invokes the built-in eval() function in Python via system(). But it is not very efficient because the resulting value is once written to an external file (and also the overhead to call Python itself). So if efficiency matters, it may be better to use more specific 3rd-party libraries, or for handiness, work with interpreted languages directly. (I suggest the latter approach if the calculation is not too demanding, because it saves much time for coding...)

Python:

from __future__ import print_function, division
from math import *
str = input( "Input an expression: " )
x = 1.0
y = 2.0
print( eval( str ) )   # if you type "x + 10 * y" in the prompt, you get 21

Julia:

println( "Input an expression: " )
str = readline()
x = 1.0
y = 2.0
println( eval( parse( str ) ) )


[ EDIT ]

If it is OK to use system() and write external files, another option may be to simply write a small Fortran code that contains the expression to be evaluated, compile and run it via system(), get the result via an external file. For example, if we replace the two lines in the above code (write( cmd, "(a)" ) ... and system( trim( cmd ) )) by the following, it gives the same result. This might be useful if we want to keep the code entirely written in Fortran, with minimal effort for modification.

    open( newunit=u, file="tmp.f90" )
    write( u, "(a)" ) "implicit none"
    write( u, "(a)" ) "real :: x, y"
    write( u, "(a)" ) trim(sx)
    write( u, "(a)" ) trim(sy)
    write( u, "(a)" ) "write(*,'(e30.20)') " // trim(expr)
    write( u, "(a)" ) "end"
    close( u )

    call system( "gfortran -fdefault-real-8 -ffree-line-length-none tmp.f90 && ./a.out > tmp.dat" )
         ! Assuming bash on Linux or Mac (x86_64).
         ! -fdefault-real-8 is attached to promote 1.0 etc to 8-byte floating-point values.

    call system( "rm -f tmp.f90" )

这篇关于I / O中的数值表达式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-19 11:14