第一次接触Fortran的输入输出时,我完全被那些星号和括号搞晕了。但后来发现,只要掌握几个核心语句,就能轻松处理科学计算中的数据读写。让我们从最基础的read和write开始,就像学骑自行车一样,先学会保持平衡再玩花样。
read语句就像个听话的助手,专门负责从各种渠道获取数据。最常见的是从键盘读取输入,比如下面这个例子:
fortran复制program basic_read
implicit none
integer :: age
print *, "请输入您的年龄:"
read(*, *) age
print *, "您输入的年龄是:", age
end program
这个小程序会先提示用户输入年龄,然后把输入的数值存到age变量中。这里的read(*, *)第一个星号表示从键盘读取,第二个星号表示使用默认格式。我刚开始总记不住这两个星号的区别,后来发现可以想象成"从哪里读"和"怎么读"。
write语句则是read的好搭档,负责把数据输出到屏幕或文件。它的基本结构和read很像:
fortran复制program basic_write
implicit none
real :: temperature = 36.5
write(*, *) "当前体温:", temperature
end program
这里write(*, *)的第一个星号表示输出到屏幕,第二个星号同样表示默认格式。在实际项目中,我经常用write来输出计算结果,比print更灵活,因为可以指定输出位置。
print语句是write的简化版,只能输出到屏幕,但写起来更简洁:
fortran复制program basic_print
implicit none
character(len=20) :: name = "Fortran新手"
print *, "欢迎你,", name
end program
这三种语句构成了Fortran输入输出的基础。刚开始可能会混淆它们的用法,但多写几个小程序就能掌握。我建议新手先从print开始,等熟悉了再过渡到更灵活的write。
当我在实验室第一次看到导师的Fortran代码时,那些整齐排列的数据表格让我惊叹不已。后来才知道,这都是格式化输出的功劳。格式化就像给数据穿衣服,既美观又实用。
整数格式化最常用的是Iw描述符,其中I表示整数,w表示宽度。来看个实际例子:
fortran复制program int_format
implicit none
integer :: small = 5, large = 12345
write(*, "(I5)") small ! 输出" 5"
write(*, "(I5)") large ! 输出"12345"
write(*, "(I3)") large ! 输出"***" (宽度不足)
end program
这里有几个实用技巧:
I0让输出宽度自动匹配数字长度nIw简写,比如3I5相当于I5,I5,I5我在处理实验数据时发现,当不确定数字大小时,先用I0测试,再确定固定宽度最稳妥。
实数格式化比整数复杂,因为有小数点和科学计数法。最常用的是Fw.d格式:
fortran复制program real_format
implicit none
real :: precise = 3.1415926
write(*, "(F8.3)") precise ! 输出" 3.142"
write(*, "(F6.2)") precise ! 输出" 3.14"
write(*, "(F4.1)") precise ! 输出"****" (宽度不足)
end program
科学计数法用Ew.d或ESw.d,后者是IEEE标准格式:
fortran复制program science_format
implicit none
real :: tiny = 1.234e-8, huge = 5.678e12
write(*, "(ES12.3)") tiny ! 输出" 1.234E-08"
write(*, "(E10.2)") huge ! 输出"0.57E+13"
end program
记住一个经验法则:科学计数法的宽度w至少要是d+7,否则可能显示不全。
当我能熟练使用基本格式化后,发现Fortran还藏了很多"秘密武器",能让输出更加专业。
nX描述符用来插入空格特别方便:
fortran复制program space_demo
implicit none
integer :: a=1, b=2, c=3
write(*, "(I0,2X,I0,2X,I0)") a, b, c ! 输出"1 2 3"
end program
/描述符实现换行,我经常用它来分隔数据块:
fortran复制program newline_demo
implicit none
real :: x(3) = [1.1, 2.2, 3.3]
write(*, "(F5.2,/,F5.2,/,F5.2)") x ! 每个数单独一行
end program
Tc和TLn/TRn能精确定位输出位置:
fortran复制program position_demo
implicit none
write(*, "(T10, '第10列', TL5, '第5列', TR3, '第8列')")
end program
这个特性在生成固定格式报表时特别有用,我经常用它来对齐表格标题和数据。
SP和SS控制是否显示正号:
fortran复制program sign_demo
implicit none
integer :: num = 5
write(*, "(SP,I2,SS,I2)") num, num ! 输出"+5 5"
end program
进制转换描述符B、O、Z:
fortran复制program base_demo
implicit none
integer :: n = 15
write(*, "(B8, O4, Z3)") n, n, n ! 输出"00001111 0017 00F"
end program
格式化不仅适用于输出,输入时同样重要。我在处理实验数据文件时深刻体会到了这点。
BN和BZ控制空格处理:
fortran复制program blank_demo
implicit none
integer :: a, b
read(*, "(BN,I5)") a ! 输入"1 "会被当作100
read(*, "(BZ,I5)") b ! 输入"1 "会被当作1
end program
kP缩放因子特别适合处理科学数据:
fortran复制program scale_demo
implicit none
real :: value
read(*, "(2PF10.3)") value ! 输入123.456实际得到1.23456
end program
经过多个科研项目的磨练,我总结了这些实用建议:
I0、F0.2等自动宽度格式测试,再确定固定宽度ES而非E,更符合现代标准fortran复制program format_reuse
implicit none
integer :: i
real :: x
character(len=10) :: name
100 FORMAT(I3,2X,F6.2,2X,A)
do i = 1, 3
x = i * 3.14
write(name, "(A,I1)") "数据",i
write(*,100) i, x, name
end do
end program
这个例子展示了如何用FORMAT语句保持多行输出格式一致。刚开始我觉得这种写法有点老派,但在处理复杂输出时确实能减少重复代码。