Fortran Coder

查看: 2653|回复: 2

Fortran编程技巧(持续更新)

[复制链接]

122

帖子

34

主题

1

精华

大师

F 币
1107 元
贡献
584 点
发表于 2022-10-26 13:50:05 | 显示全部楼层 |阅读模式
本帖最后由 weixing1531 于 2023-3-12 21:31 编辑

学习Fortran已有近20年,收集了一些编程技巧。
(1)修改老程序goto语句
先构造一个只执行一次的命名循环,再使用exit退出命名循环从而避免使用goto语句
老程序
[Fortran] 纯文本查看 复制代码
if(...)then
  语句A
  goto 99
end if
if(...)then
  语句B
  goto 99
end if
语句C
99 语句D

等价于新程序
[Fortran] 纯文本查看 复制代码
out:do i=1,1
  if(...)then
    语句A
    exit out
  end if
  if(...)then
    语句B
    exit out
  end if
  语句C
end do out
语句D

(2)整数转换为字符串
[Fortran] 纯文本查看 复制代码
!整数转换为字符串
pure function int2str(i) result(f_string) !摘自fpm源代码
    integer,intent(in)::i !i为要转换的整数
    character(len=str_int_len(i))::f_string !自动字符串 调用已有函数str_int_len 7.3Automatic objects《Mordern Fortran Explained 2018》P120
    
    write(f_string,"(i0)")i !f_string长度必须明确
end function int2str
!> Returns the length of the string representation of 'i'
pure integer function str_int_len(i) result(sz) !摘自fpm源代码
    integer, intent(in) :: i
    integer, parameter :: MAX_STR = 255 !字符串最大长度
    character(MAX_STR) :: s
    ! If 's' is too short (MAX_STR too small), Fortran will abort with:
    ! "Fortran runtime error: End of record"
    write(s, '(i0)') i !左对齐 F202X标准才支持s为递延字符串
    sz = len_trim(s) !删除尾部空格后的字符串长度
end function str_int_len

(3)浮点数转换为字符串
[Fortran] 纯文本查看 复制代码
pure function real2str(MXS,ld) result(res) !浮点数转换为字符串 调用str_int_len、int2str函数
    real(real64),intent(in)::MXS !浮点数
    integer,intent(in)::ld !小数保留位数
    character(len=:),allocatable::res,ft !递延长度字符串
    character(len=255)::str
    integer::i
    
    i=nint(MXS) !浮点数四舍五入取整 避免重复计算
    
    select case(ld)
        case(0) !浮点数四舍五入取整
            res=int2str(i) !不需要ft
        case(1:4) !小数保留1-4位
            ft="(f"//int2str(str_int_len(i)+ld+1)//"."//int2str(ld)//")" !"(fX.Y)" 浮点数格式 Y为小数点保留位数 X为总字符串长度(整数部分+小数点+小数部分)
            write(str,ft)MXS !浮点数转换为字符串 左对齐 只能用str而不能用res F202X标准才支持str为递延字符串
            res=trim(str) !删除尾部空格
            deallocate(ft) !释放递延字符串内存 不能放在函数尾部 否则浮点数四舍五入取整无法计算
        case default
            error stop "小数保留位数超出范围!"
    end select
end function real2str

(4)C字符串指针转换Fortran字符串

[Fortran] 纯文本查看 复制代码
FUNCTION C_to_F_string(c_string_pointer) RESULT(f_string) !C字符串指针转换Fortran字符串
        USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_PTR, C_F_POINTER, C_CHAR, C_NULL_CHAR
        type(C_PTR), INTENT(IN) :: c_string_pointer !C字符串指针
        CHARACTER(LEN=:), ALLOCATABLE :: f_string !延迟长度字符串
        CHARACTER(KIND=C_CHAR), DIMENSION(:), POINTER :: char_array_pointer => NULL() !Fortran字符数组指针
        CHARACTER(LEN=255) :: aux_string
        INTEGER :: i, length=0

        CALL C_F_POINTER(c_string_pointer, char_array_pointer, [255]) !C字符串指针转换为Fortran字符数组指针

        IF (.NOT.ASSOCIATED(char_array_pointer)) THEN !char_array_pointer为空指针
            ALLOCATE(CHARACTER(LEN=4)::f_string)
            f_string="NULL"
            return
        END IF

        aux_string=" "

        DO i=1,255
            IF (char_array_pointer(i)==c_null_char) THEN !达到字符串尾部
                length=i-1
                EXIT
            END IF

            aux_string(i:i)=char_array_pointer(i) !逐个元素复制字符
        END DO

        ALLOCATE(CHARACTER(LEN=length)::f_string)
        f_string=aux_string(1:length)
END FUNCTION C_to_F_string

(5)读写Excel数据
方法一:商业库Libxl提供了Fortran函数接口,序列号需要破解
https://www.libxl.com/
方法二:先读写csv文件,然后手动另存为xls格式
Github网上有现成的csv模块,作者:Jacob Williams
(6)日期与时间操作
Github网上有现成的datetime模块
https://github.com/wavebitscientific/datetime-fortran
(7)常用数值计算算法原代码
Numerical Recipe、宋叶志、何光渝、徐士良
(8)生成随着时间与日期变动的动态密码
[Fortran] 纯文本查看 复制代码
impure function GetPassword(PasswordLen,IsDay) !获得动态密码及长度
    integer,intent(out)::PasswordLen
    logical,intent(in),optional::IsDay !动态密码是否日变化
    character(len=:),allocatable::GetPassword !递延长度字符串
    character(8)  :: date,temp !CCYYMMDD
    character(10) :: time !HHMMSS.SSS
    
    call date_and_time(date,time) !返回当前日期与时间
    temp=date(3:8)//time(1:2) !界面进入原始密码 为与时间有关的动态密码YYMMDDHH 两位年月日时
    
    if(present(IsDay))then
        if(IsDay)temp=date(1:8) !界面进入密码 为与日期有关的动态密码CCYYMMDD 四位年月日
    end if
    
    GetPassword="Wx"
    GetPassword=GetPassword//temp(2:8)//temp(1:1) !加工后密码
    PasswordLen=len(GetPassword) !输出密码字符串长度
end function

(9)判断整数变量b的值是否与一维整数数组a的任意元素相等
方法一:
[Fortran] 纯文本查看 复制代码
Any(a(:)==b) !T相等F不相等

方法二:
[Fortran] 纯文本查看 复制代码
FindLoc(a(:),b)==[0] !F相等T不相等
(10)如何判断两个字符串完全相等
[Fortran] 纯文本查看 复制代码
character(:),allocatable::a,b
a="A"
b="A " !A后面加一个空格
write(*,*)a==b !你以为打印F 其实打印T
write(*,*)(a==b .AND. (len(a)==len(b))) !打印F

(11)如何在主程序中修改模块protected属性变量?将该变量修改包裹在模块方法之中,然后在主程序调用模块方法
(12)常用参考网站
https://fortranwiki.org/fortran/show/HomePage
https://fortran-lang.org/
https://jblevins.org/mirror/amiller/











评分

参与人数 1F 币 +5 贡献 +3 收起 理由
fcode + 5 + 3 赞一个!

查看全部评分

1938

帖子

12

主题

5

精华

论坛跑堂

臭石头雪球

F 币
1255 元
贡献
529 点

美女勋章热心勋章星光勋章新人勋章贡献勋章管理勋章帅哥勋章爱心勋章规矩勋章元老勋章水王勋章

发表于 2022-10-28 08:53:15 | 显示全部楼层
楼主这个帖子主题不错。我也来一个技巧。

善用常量数组来替代一些 if else。
比如,经典的考试题目,星期一看电影,星期二看书,星期三聚会,星期四野营,星期五星期六旅行,星期日休息。
输入星期几,输出要做的事情。

普通代码:
[Fortran] 纯文本查看 复制代码
program fcode_cn
  integer :: wk
  read(*,*) wk
  select case(wk)
  case (1)
    write(*,*) "看电影"
  case (2)
    write(*,*) "看书"
  case (3)
    write(*,*) "聚会"
  case (4)
    write(*,*) "野营"
  case (5,6)
    write(*,*) "旅行"
  case (7)
    write(*,*) "休息"
  end select
end program fcode_cn


利用常量数组代码:
[Fortran] 纯文本查看 复制代码
program fcode_cn
  character(len=6) , parameter :: ACT(*) = &
    [character(len=6)::"看电影","看书","聚会","野营","旅行","旅行","休息"]
  integer :: wk
  read(*,*) wk
  write(*,*) ACT(wk)
end program fcode_cn


可以看到,合理的使用常量数组,不但代码简练,并且易于维护,以后增加和修改都更简单。
同时,也便与遍历整个星期。
[Fortran] 纯文本查看 复制代码
  do i = 1 , size(ACT)
    write(*,*) ACT(i)
  end do

1

帖子

0

主题

0

精华

新人

F 币
28 元
贡献
6 点
发表于 2022-11-11 02:22:48 | 显示全部楼层
fcode 发表于 2022-10-28 08:53
楼主这个帖子主题不错。我也来一个技巧。

善用常量数组来替代一些 if else。

学习了 这个方法真的好用
您需要登录后才可以回帖 登录 | 极速注册

本版积分规则

捐赠本站|Archiver|关于我们 About Us|小黑屋|Fcode ( 京ICP备18005632-2号 )

GMT+8, 2024-2-25 20:11

Powered by Tencent X3.4

© 2013-2024 Tencent

快速回复 返回顶部 返回列表