This commit is contained in:
2025-09-25 16:33:13 +08:00
commit 88fdb762e0
15 changed files with 7983 additions and 0 deletions

319
指针测试.f90 Normal file
View File

@ -0,0 +1,319 @@
program example
implicit none
call test
call test2
end program example
module ModDoLinkList
implicit none
integer, parameter :: sgl=selected_real_kind(p=1)
type :: doNode
real(sgl) :: var1
type(doNode), pointer :: before
type(doNode), pointer :: next
end type
contains
recursive subroutine DoNodeAdd(newNode, ptr)
type(doNode), intent(inout), pointer :: newNode
type(doNode), intent(inout), pointer :: ptr
if ( .not. associated(newNode) ) stop ""
if ( associated(ptr) ) then
if ( associated(ptr%next) ) then
call DoNodeAdd(newNode, ptr%next)
else
ptr%next => newNode
newNode%before => ptr
end if
else
ptr => newNode
end if
end subroutine DoNodeAdd
subroutine test1(value, ptr)
type(doNode), intent(inout), target :: value
type(doNode), intent(inout), pointer :: ptr
type(doNode), pointer :: temp => null()
type(doNode), target :: a
type(doNode), pointer :: newNode => null()
allocate(newNode)
newNode%var1 = 200.
newNode%before => null()
newNode%next => null()
a%var1 = 100.
a%before => null()
a%next => null()
temp => value%before
temp%next => a
write(*, *)
write(*, *) '如果传递的是值, 则 ', value%var1
temp => ptr%before
ptr%before%next => a
write(*, *) '如果传递的是指针, 则 ', ptr%var1
newNode%before => ptr ! 插入结点前指针 => 操作结点
temp => ptr%next
temp%before => newNode ! 操作结点后指针指向的结点的前指针 => 插入结点
newNode%next => temp ! 插入结点的后指针 => 操作结点后指针指向的结点
ptr%next => newNode
end subroutine
recursive subroutine DoNodeSortForword(newNode, ptr) ! 向前排序
implicit none
type(doNode), intent(inout), target :: newNode ! 插入结点
type(doNode), intent(inout), target :: ptr ! 操作结点
type(doNode), pointer :: temp
write(*, *) '当前操作结点为: ', ptr%var1, '; 当前插入结点为:', newNode%var1
! if ( .not. associated(newNode) ) then ! 如果插入结点未关联
! stop "" ! 报错退出
! else ! 如果插入结点已关联
write(*, *) ' 插入结点存在'
if ( newNode%var1 < ptr%var1 ) then ! 如果插入结点值比操作结点值小
write(*, *) ' 插入结点值小于操作结点值'
if ( associated(ptr%before) ) then ! 如果操作结点前指针已关联
write(*, *) ' 由于操作结点值前指针已关联, 检测前一结点'
call DoNodeSortForword(newNode, ptr%before) ! 递归调用
else ! 如果操作结点前指针为空
write(*, *) ' 由于操作结点值前指针未关联, 则在最前端插入插入节点'
ptr%before => newNode ! 操作结点前指针 => 插入结点
newNode%next => ptr ! 插入结点后指针 => 操作节点
end if
else ! 如果插入结点值比操作结点值大
write(*, *) ' 插入结点值大于操作结点值, 将结点插入操作结点之后'
newNode%before => ptr ! 插入结点前指针 => 操作结点
write(*, *) ' 插入结点前指针指向: ', newNode%before%var1
temp => ptr%next
! ptr%next => newNode ! 操作结点的后指针 => 插入结点
temp%before => newNode ! 操作结点后指针指向的结点的前指针 => 插入结点
write(*, *) ' 操作结点后结点前指针指向:', temp%before%var1
newNode%next => temp ! 插入结点的后指针 => 操作结点后指针指向的结点
write(*, *) ' 插入结点后指针指向: ', newNode%next%var1
ptr%next => newNode
write(*, *) ' 操作结点后指针指向: ', ptr%next%var1
end if
! if ( .not. associated(ptr) ) then ! 如果操作结点前指针为空
! write(*, '(A)', advance='no') '10'
! ptr%before => newNode !
! newNode%next => ptr
! else
! write(*, '(A)', advance='no') '11'
! if ( newNode%var1 < ptr%var1 ) then
! call DoNodeSortForword(newNode, ptr%before)
! else
! newNode%before => ptr
! ptr%next%before => newNode
! newNode%next => ptr%next
! ptr%next => newNode
! end if
! end if
! newNode => null()
call DoNodePrint1(ptr)
write(*, *)
! ptr => null()
! end if
end subroutine DoNodeSortForword
recursive subroutine DoNodeSortForword1(newNode, ptr) ! 向前排序
implicit none
type(doNode), intent(in), pointer :: newNode ! 插入结点
type(doNode), intent(in), pointer :: ptr ! 操作结点
type(doNode), pointer :: temp
write(*, *) '当前操作结点为: ', ptr%var1, '; 当前插入结点为:', newNode%var1
if ( .not. associated(newNode) ) then ! 如果插入结点未关联
stop "" ! 报错退出
else ! 如果插入结点已关联
write(*, *) ' 插入结点存在'
if ( newNode%var1 < ptr%var1 ) then ! 如果插入结点值比操作结点值小
write(*, *) ' 插入结点值小于操作结点值'
if ( associated(ptr%before) ) then ! 如果操作结点前指针已关联
write(*, *) ' 由于操作结点值前指针已关联, 检测前一结点'
call DoNodeSortForword1(newNode, ptr%before) ! 递归调用
else ! 如果操作结点前指针为空
write(*, *) ' 由于操作结点值前指针未关联, 则在最前端插入插入节点'
ptr%before => newNode ! 操作结点前指针 => 插入结点
newNode%next => ptr ! 插入结点后指针 => 操作节点
end if
else ! 如果插入结点值比操作结点值大
! write(*, *) ' 插入结点值大于操作结点值, 将结点插入操作结点之后'
! newNode%before => ptr ! 插入结点前指针 => 操作结点
! write(*, *) ' 插入结点前指针指向: ', newNode%before%var1
! temp => ptr%next
! ptr%next => newNode ! 操作结点的后指针 => 插入结点
! ptr%next%before => newNode ! 操作结点后指针指向的结点的前指针 => 插入结点
! write(*, *) ' 操作结点后结点前指针指向:', temp%before%var1
! newNode%next => ptr%next ! 插入结点的后指针 => 操作结点后指针指向的结点
! write(*, *) ' 插入结点后指针指向: ', newNode%next%var1
! ptr%next => newNode
! write(*, *) ' 操作结点后指针指向: ', ptr%next%var1
!
! newNode%before => ptr
! newNode%next => ptr%next
! ptr%next => newNode
! newNode%next%before => newNode
!
write(*, *) ptr%next%var1
newNode%before => ptr
write(*, *) ptr%next%var1
temp => ptr%next
write(*, *) ptr%next%var1
! temp%before => newNode
write(*, *) ptr%next%var1
newNode%next => ptr%next
write(*, *) ptr%next%var1
! ptr%next => newNode
newNode%next%before => newNode
! ptr%next%before => newNode
write(*, *) ptr%next%var1
ptr%next => newNode
write(*, *) ptr%next%var1, newNode%next%var1
end if
call DoNodePrint1(ptr)
write(*, *)
end if
end subroutine DoNodeSortForword1
recursive subroutine DoNodePrint(ptr)
type(doNode), intent(in), pointer :: ptr
if ( associated(ptr) ) then
write(*, '(F6.2)', advance='no') ptr%var1
call DoNodePrint(ptr%next)
end if
end subroutine DoNodePrint
recursive subroutine DoNodePrint1(ptr)
type(doNode), intent(in), pointer :: ptr
if ( associated(ptr) ) then
write(*, '(F6.2)', advance='no') ptr%var1
call DoNodePrint1(ptr%before)
end if
end subroutine DoNodePrint1
end module ModDoLinkList
subroutine Test
use ModDoLinkList
implicit none
type(doNode), pointer :: newNode => null()
type(doNode), pointer :: head => null()
type(doNode), pointer :: tail => null()
type(doNode), pointer :: ptr => null()
real(sgl) :: temp
integer :: i
integer :: errorLevel
do i = 1, 21
allocate(newNode)
newNode%var1 = real(i)
newNode%before => null()
newNode%next => null()
if ( .not. associated(head) ) head => newNode
! if ( .not. associated(head) ) then
! head => newNode
! write(*, *) '已插入首结点 ', newNode%var1
! else
! call DoNodeAdd(newNode, head)
! write(*, *) '已插入结点 ', newNode%var1
! end if
call DoNodeAdd(newNode, tail)
tail => newNode
end do
allocate(newNode)
newNode%var1 = 17.5
newNode%before => null()
newNode%next => null()
ptr => head
do
if ( associated(ptr) ) then
write(*, '(F6.2)', advance='no') ptr%var1
ptr => ptr%next
else
exit
end if
end do
write(*, *)
ptr => tail
call DoNodeSortForword1(newNode, ptr)
call DoNodePrint(head)
write(*, *)
call DoNodePrint1(tail)
write(*, *)
do
if ( associated(head%before) ) then
head => head%before
else
exit
end if
end do
ptr => tail
ptr => head
write(*, *)
do
if ( associated(ptr) ) then
write(*, '(F6.2)', advance='no') ptr%var1
! write(*, *) '当前结点值为:', ptr%var1, '; 下一结点值为:', ptr%before%var1
! ptr => ptr%before
ptr => ptr%next
else
exit
end if
end do
ptr => tail%before
call test1(ptr, ptr)
write(*, *) ptr%before%var1, ptr%var1, ptr%next%var1, ptr%next%next%var1
end subroutine Test
subroutine test2
use ModDoLinkList
integer :: i
type(doNode), pointer :: newNode
type(doNode), pointer :: head
type(doNode), pointer :: middle
type(doNode), pointer :: tail
type(doNode), pointer :: ptr
allocate(newNode)
newNode%var1 = 1.
newNode%before => null()
newNode%next => null()
head => newNode
allocate(newNode)
newNode%var1 = 2.
newNode%before => null()
newNode%next => null()
head%next => newNode
newNode%before => head
middle => newNode
allocate(newNode)
newNode%var1 = 3.
newNode%before => null()
newNode%next => null()
middle%next => newNode
newNode%before => middle
tail => newNode
write(*, *) head%var1, middle%var1, tail%var1
! head%next => tail
! write(*, *) head%next%var1, middle%var1
! head%next%next => head
! write(*, *) head%next%next%var1, middle%next%var1, tail%var1
! ptr => head%next
! head%next => tail
! middle%var1 = 4.
! write(*, *) ptr%var1, head%next%var1
allocate(newNode)
newNode%var1 = 4.
newNode%before => null()
newNode%next => null()
newNode%before => middle
newNode%next => middle%next
! middle%next => newNode
! newNode%next%before => newNode
middle%next%before => newNode
middle%next => newNode
ptr => head
do
if ( associated(ptr) ) then
write(*, '(F10.2)', advance='no') ptr%var1
ptr => ptr%next
else
exit
end if
end do
write(*, *)
ptr => tail
do
if ( associated(ptr) ) then
write(*, '(F10.2)', advance='no') ptr%var1
ptr => ptr%before
else
exit
end if
end do
write(*, *)
end subroutine

56
程序模板.f90 Normal file
View File

@ -0,0 +1,56 @@
! ==============================================================================
! 通过 gfortran ./test.f90 -o ./run && ./run 运行
! 程序名:
!
! 目的:
!
! 修订记录:
! 日期 编程者 改动描述
! =================== ============= =====================================
!
! 程序结构:
!
! ==============================================================================
! 模块:
module ModName
implicit none
! 数据字典
! 声明常数
REAL, PARAMETER :: PI=3.14159265 ! PI值
REAL, PARAMETER :: e=2.718281828459 ! 自然对数
INTEGER, PARAMETER :: arrayLength=20 ! 数组基准长度
! 声明变量
! 创建显式接口
contains
subroutine SubName(varName1,varName2)
implicit none
! 数据字典
end subroutine SubName
end module ModName
! ==============================================================================
! 主程序:
program ProName
use ModName
implicit none
! 数据字典
! 声明常量
! 声明变量
! 变量初始化
! 数据输入
! 运算过程
! 结果输出
end program ProName
! ==============================================================================
! 子程序
! subroutine SubName(varName1,varName2)
! use MouName
! implicit none
! Type, intent(inout) :: varName
! end subroutine SubName
! ==============================================================================
! 函数
! function FunName(varName1,varName2)
! use MouName
! implicit none
! end function FunName
! ==============================================================================

641
第10章习题.f90 Normal file
View File

@ -0,0 +1,641 @@
! ==============================================================================
! 通过 gfortran ./test.f90 -o ./run && ./run 运行
! 程序名:
! 第10章习题及书上例题
! 目的:
!
! 修订记录:
! 日期 编程者 改动描述
! =================== ============= =====================================
! 2021-05-10 17:15:53 Sola 测验10-1 4 判断星期几
! 2021-05-10 17:22:01 Sola 测验10-1 5 字符串反序
! 2021-05-10 17:33:13 Sola 测验10-1 6-8 测试字符
! 2021-05-10 18:14:05 Sola 例题10-3 转换输出数值格式
! 2021-05-10 21:58:38 Sola 测验10-2 3
! 2021-05-11 14:30:07 Sola 习题10-4 字符串转大写
! 2021-05-11 15:00:14 Sola 习题10-5 字符串转小写
! 2021-05-11 16:03:39 Sola 习题10-8 首字母大写
! 2021-05-11 17:39:18 Sola 习题10-9 10-8可变函数版(话说直接写的就是可变函数版本的...)
! 2021-05-11 17:39:48 Sola 习题10-10 检测字符中实际字符数
! 2021-05-11 18:16:41 Sola 习题10-11 检测第一个和最后一个非空字符位置(话说上一题的函数改一改不就是了)
! 2021-05-11 19:10:54 Sola 习题10-12 输入参数文件
! 2021-05-11 21:51:02 Sola 习题10-13 直方图 ??? 这是什么鬼需求
! 2021-05-12 11:28:44 Sola 习题10-14 随机数直方图
! 2021-05-12 13:18:26 Sola 习题10-15 拷贝文件去除注释
! 程序结构:
!
! ==============================================================================
! 模块:
module Chapter10
implicit none
! 数据字典
! 声明常数
REAL, PARAMETER :: PI=3.14159265 ! PI值
REAL, PARAMETER :: e=2.718281828459 ! 自然对数
INTEGER, PARAMETER :: arrayLength=20 ! 数组基准长度
! 声明变量
! 创建显式接口
contains
end module Chapter10
! ==============================================================================
! 主程序:
program ProName
! use ModName
implicit none
! 数据字典
! 声明常量
! 声明变量
! 变量初始化
! 数据输入
! 运算过程
! 结果输出
! call Exercises10_1_4
! call Exercises10_1_5
! call Exercises10_1_6_8
! call Example10_3
! call Exercises10_2_3
! call Exercises10_4
! call Exercises10_10
! call Exercises10_12
! call Exercises10_13
! call Exercises10_14
call Exercises10_15
end program ProName
! ==============================================================================
! 子程序
! subroutine SubName(varName1,varName2)
! use MouName
! implicit none
! Type, intent(inout) :: varName
! end subroutine SubName
! ==============================================================================
! 函数
! function FunName(varName1,varName2)
! use MouName
! implicit none
! end function FunName
! ==============================================================================
! 测试10-1 4 判断星期几
subroutine Exercises10_1_4
implicit none
integer :: i
write(*,*) (day(i), i = 7, 1, -1)
contains
function day(iday)
integer, intent(in) :: iday
character(len=3) :: day
character(len=3), dimension(7) :: days=(/'SUN', 'MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT'/)
if ( (iday>=1) .and. (iday<=7) ) then
day = days(iday)
end if
end function day
end subroutine Exercises10_1_4
! 测试10-1 5 字符串反序
subroutine Exercises10_1_5
implicit none
write(*,*) swap_string('Hello World!')
contains
function swap_string(string)
character(len=*), intent(in) :: string
character(len=len(string)) :: swap_string
integer :: length, i
length = len(string)
do i = 1, length
swap_string(length-i+1: length-i+1) = string(i: i)
end do
end function swap_string
end subroutine Exercises10_1_5
! 测验10-1 6-8
subroutine Exercises10_1_6_8
implicit none
call sub1
call sub2
call sub3
contains
subroutine sub1
character(len=20) :: last='JOHNSON'
character(len=20) :: first='JAMES'
character :: middle_initial='R'
character(len=42) :: name
write(*,*) middle_initial
name = last //', '//first//middle_initial
write(*,*) name
end subroutine sub1
subroutine sub2
character(len=4) :: a='123'
character(len=12) :: b
b = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
write(*,*) a, ', ', b
b(5: 8) = a(2: 3)
write(*,*) a, ', ', b
end subroutine sub2
subroutine sub3
character(len=80) :: line
integer :: ipos1, ipos2, ipos3, ipos4
line = 'This is a test line containing some input data!'
ipos1 = index(line, 'in')
ipos2 = index(line, 'Test')
ipos3 = index(line, 't l')
ipos4 = index(line, 'in', .TRUE.)
write(*,*) ipos1, ipos2, ipos3, ipos4
end subroutine sub3
end subroutine Exercises10_1_6_8
! 例题10-3 转换输出数值格式
subroutine Example10_3
implicit none
real :: input
character(len=1) :: runLevel
outer:do
write(*, *) '请输入数值:'
read(*, *) input
write(*, *) '输出的结果为:', num2str(input)
inner:do
write(*, *) '是否接着输入下一个数值? 继续(Y)/结束(N)'
read(*, *) runLevel
if ( runLevel == 'Y' .or. runLevel == 'y' ) then
exit inner
else if ( runLevel == 'N' .or. runLevel == 'n' ) then
exit outer
else
write(*,*) '非法输入! 请重新输入!'
end if
end do inner
end do outer
contains
function num2str(num)
character(len=12) :: num2str ! 函数输出类型
real, intent(in) :: num ! 输入实数
if ( abs(num) <= 9999999. .and. abs(num) >= 0.01 .or. num == 0 ) then
write(num2str, '(F12.4)') num
else
write(num2str, '(ES12.5)') num
end if
end function num2str
end subroutine Example10_3
! 测验10-2 3
subroutine Exercises10_2_3
implicit none
character(len=30) :: line = '123456789012345678901234567890'
character(len=30) :: fmt = '(3X, I6, 12X, I3, F6.2)'
integer :: ival1, ival2
real :: rval3
read (line, fmt) ival1, ival2, rval3
write(*,*) ival1, ival2, rval3
end subroutine Exercises10_2_3
! 习题10-4 字符串转大写
subroutine Exercises10_4
implicit none
character(len=132) :: input
character :: runLevel
outer:do
write(*, *) '请输入一段字符小于132字包含空格字符请用引号括起'
read(*, *) input
write(*, *) '转换大写结果为:', Ucase(input)
write(*, *) '转换小写结果为:', Lcase(input)
write(*, *) '首字符大写结果为:', Caps(input)
inner:do
write(*, *) '是否接着转换下一个字符串? 继续(Y)/结束(N)'
read(*, *) runLevel
if ( runLevel == 'Y' .or. runLevel == 'y' ) then
exit inner
else if ( runLevel == 'N' .or. runLevel == 'n' ) then
exit outer
else
write(*,*) '非法输入! 请重新输入!'
end if
end do inner
end do outer
contains
! 转换为大写
function Ucase(str)
character(len=*), intent(in) :: str ! 定义输入字符串
character(len=len(str)) :: ucase ! 定义函数类型
integer :: i ! 循环参数
do i = 1, len(str) ! 对输入每个字符循环
if ( lge(str(i: i), 'a') .and. lle(str(i: i), 'z') ) then ! 如果字符在a~z中
Ucase(i: i) = achar( iachar(str(i: i)) - 32 ) ! 输出大写
else
Ucase(i: i) = str(i: i) ! 如果不在, 输出原字符
end if
end do
end function Ucase
! 转换为小写
function Lcase(str)
character(len=*), intent(in) :: str ! 定义输入字符串
character(len=len(str)) :: Lcase ! 定义函数类型
integer :: i ! 循环参数
do i = 1, len(str) ! 对每个输入字符循环
if ( lge(str(i: i), 'A') .and. lle(str(i: i), 'Z') ) then ! 如果字符在A~Z中
Lcase(i: i) = achar( iachar(str(i: i)) + 32 ) ! 输出小写
else
Lcase(i: i) = str(i: i) ! 如果不再, 输出原字符
end if
end do
end function Lcase
! 首字符大写
! 情况可能如下:
! 1. 小写字母, runLevel .eqv. .TRUE. 转换为大写, runLevel = .FALSE.
! 2. 小写字母, runLevel .eqv. .FALSE. 不变
! 3. 大写字母, runLevel .eqv. .TRUE. 不变, runLevel = .FALSE.
! 4. 大写字母, runLevel .eqv. .FALSE. 转换为小写
! 5. 非字符, runLevel = .TRUE.
function Caps(str)
character(len=*), intent(in) :: str ! 输入字符
character(len=len(str)) :: Caps ! 定义函数类型
integer :: i ! 循环参数
logical :: runLevel ! 运行级别(判断是否为首字母)
runLevel = .TRUE. ! 初始化运行级别
do i = 1, len(str) ! 遍历每个字符
if ( lge(str(i: i), 'a') .and. lle(str(i: i), 'z') .and. ( runLevel .eqv. .TRUE. ) ) then ! 小写字母为首字母
Caps(i: i) = achar( iachar(str(i: i)) - 32 ) ! 转换为大写字母
runLevel = .FALSE. ! 下一个字符非首字母
elseif ( lge(str(i: i), 'a') .and. lle(str(i: i), 'z') .and. ( runLevel .eqv. .FALSE. ) ) then ! 小写字母非首字母
Caps(i: i) = str(i: i) ! 不改变字符
elseif ( lge(str(i: i), 'A') .and. lle(str(i: i), 'Z') .and. ( runLevel .eqv. .TRUE. ) ) then ! 大写字母为首字母
Caps(i: i) = str(i: i) ! 不改变字符
runLevel = .FALSE. ! 下一个字符非首字母
elseif ( lge(str(i: i), 'A') .and. lle(str(i: i), 'Z') .and. ( runLevel .eqv. .FALSE. ) ) then ! 大写字母非首字母
Caps(i: i) = achar( iachar(str(i: i)) + 32 ) ! 转换为小写字母
elseif ( lge(str(i: i), '0') .and. lle(str(i: i), '9') ) then ! 如果是数字
Caps(i: i) = str(i: i) ! 不改变字符
runLevel = .FALSE. ! 下一个字符不是首字母
else ! 非字母
Caps(i: i) = str(i: i) ! 不改变字符
runLevel = .TRUE. ! 下一个字符是首字母(如果是字母)
end if
end do
end function Caps
end subroutine Exercises10_4
! 习题10-10 检测字符串中实际字符数量
subroutine Exercises10_10
implicit none
character(len=132) :: input
character :: runLevel
integer :: errorLevel
integer :: firstNonBlank, lastNonBlank
outer:do
write(*, *) '请输入一段字符小于132字包含空格字符请用引号括起'
read(*, *) input
write(*, *) '该字符的长度为:', LenUsed(input)
write(*, *) '该字符的允许长度为:', len(input)
write(*, *) '该字符除去尾部空格的长度为:', len_trim(input)
call NonBlank(input, firstNonBlank, lastNonBlank, errorLevel)
if ( errorLevel /= 0 ) then
write(*, *) '错误! 没有输入字符或输入字符为空!'
else
write(*, *) '第一个非空字符在第', firstNonBlank, '位, 最后一个非空字符在第', lastNonBlank, '位。'
end if
inner:do
write(*, *) '是否接着计算下一个字符串? 继续(Y)/结束(N)'
read(*, *) runLevel
if ( runLevel == 'Y' .or. runLevel == 'y' ) then
exit inner
else if ( runLevel == 'N' .or. runLevel == 'n' ) then
exit outer
else
write(*,*) '非法输入! 请重新输入!'
end if
end do inner
end do outer
contains
! 习题10-10 判断字符串中有多少字符
function LenUsed(str)
character(len=*), intent(in) :: str ! 输入字符串
integer :: LenUsed ! 定义函数返回类型
integer :: i ! 循环参数
integer :: firstSpace, lastSpace ! 首位空白字符位置
firstSpace = 0 ! 初始化变量
lastSpace = len(str)
do i = 1, lastSpace ! 判断字符串首最后一个空白字符位置
if ( str(i:i) == ' ' ) then
firstSpace = i
else
exit
end if
end do
if ( firstSpace /= lastSpace ) then ! 如果不是全部都是空白字符
do i = lastSpace, firstSpace+1, -1 ! 判断字符串尾第一个空白字符位置
if ( str(i:i) == ' ' ) then
lastSpace = i
else
exit
end if
end do
LenUsed = lastSpace - firstSpace - 1 ! 判断字符串实际使用长度
else
LenUsed = 0 ! 如果全部都是空白字符, 则长度为0
end if
end function LenUsed
! 习题10-11 判断字符串第一个和最后一个空白字符位置
subroutine NonBlank(str, firstNonBlank, lastNonBlank, errorLevel)
character(len=*), intent(in) :: str ! 输入字符串
integer :: i ! 循环参数
integer, intent(out) :: firstNonBlank, lastNonBlank ! 首位空白字符位置
integer, intent(out) :: errorLevel
firstNonBlank = len(str) ! 初始化变量
lastNonBlank = 0
do i = firstNonBlank, 1, -1 ! 判断字符串最后一个非空白位置
if ( .not. str(i:i) == ' ' ) then
lastNonBlank = i
exit
end if
end do
if ( lastNonBlank /= 0 ) then ! 如果不是全部都是空白字符
do i = 1, lastNonBlank ! 判断字符串第一个空白字符位置
if ( .not. str(i:i) == ' ' ) then
firstNonBlank = i
exit
end if
end do
errorLevel = 0
else
firstNonBlank = 0 ! 如果全部都是空白字符, 则位置为0
errorLevel = 1
end if
end subroutine NonBlank
end subroutine Exercises10_10
! 习题10-12 输入参数文件
subroutine Exercises10_12
implicit none
character(len=132) :: str
real :: start, stop, dt
logical :: plot
integer :: errorLevel
open(unit=1, status='scratch', iostat=errorLevel) ! 打开文件并输入数据
if ( errorLevel /= 0 ) stop "打开临时文件失败"
write(1, '(A)') &
&"start=0.0",&
&"stop=10.0",&
&"dt=0.2",&
&"plot on",&
&" ",&
&" "
rewind(unit=1, iostat=errorLevel) ! 回到第一行
if ( errorLevel /= 0 ) stop "操作临时文件失败"
do ! 读取文件知道文件末尾
read(1, '(A)', iostat=errorLevel) str ! 将内容赋值给字符串
if ( errorLevel /= 0 ) exit ! 判断是否到达文件末尾
call InputData(str, start, stop, dt, plot) ! 读取值
end do
write(*, *) start, stop, dt, plot ! 显示当前读取到的值
close(unit=1, iostat=errorLevel) ! 关闭临时文件
if ( errorLevel /= 0 ) stop "关闭临时文件失败" ! 检测关闭状态
contains
subroutine InputData(str, start, stop, dt, plot) ! 读取值子程序
character(len=*), intent(inout) :: str ! 输入的字符串
real, intent(out) :: start, stop, dt ! 输出数值
integer :: tempLoc ! 临时保存位置的变量
integer :: equLoc, length ! 等号位置及字符串长度
logical :: plot ! 输出逻辑值
equLoc = index(str, '=') ! 得到等号位置
length = len(str) ! 得到字符串长度
if ( equLoc == 0 ) then ! 如果没有等号
tempLoc = index( Ucase(str), 'PLOT') ! 检测全大写字符串中是否有PLOT字符
if ( tempLoc /= 0 ) then ! 如果有
if ( index(Ucase(str(1: length)), 'ON') /= 0 ) then ! 判断PLOT状态并赋值
plot = .TRUE.
elseif ( index(Ucase(str(1: length)), 'OFF') /= 0) then
plot = .FALSE.
end if
end if
return
end if
tempLoc = index( Ucase(str), 'START') ! 判断是否是START变量
if ( tempLoc /= 0 .and. tempLoc < equLoc ) then ! 如果是
write(str, '(A)') str(equLoc+1: length) ! 将值部分读入字符串
read(str, *) start ! 读取值, 接下来相同
return
end if
tempLoc = index( Ucase(str), 'STOP')
if ( tempLoc /= 0 .and. tempLoc < equLoc ) then
write(str, '(A)') str(equLoc+1: length)
read(str, *) stop
return
end if
tempLoc = index( Ucase(str), 'DT')
if ( tempLoc /= 0 .and. tempLoc < equLoc ) then
write(str, '(A)') str(equLoc+1: length)
read(str, *) dt
return
end if
end subroutine InputData
! 转换为大写
function Ucase(str)
character(len=*), intent(in) :: str ! 定义输入字符串
character(len=len(str)) :: ucase ! 定义函数类型
integer :: i ! 循环参数
do i = 1, len(str) ! 对输入每个字符循环
if ( lge(str(i: i), 'a') .and. lle(str(i: i), 'z') ) then ! 如果字符在a~z中
Ucase(i: i) = achar( iachar(str(i: i)) - 32 ) ! 输出大写
else
Ucase(i: i) = str(i: i) ! 如果不在, 输出原字符
end if
end do
end function Ucase
end subroutine Exercises10_12
! 习题10-13 直方图 ??? 这是什么鬼需求
! 基本逻辑如下:
! 1. 首先打开一个临时文件, 并向其中输入数据
! 2. 读取数据, 并向数组中填入相关值
! 3. 依据数据, 构建一个二维数组, 并模拟图表构成
! 4. 打印这个数组, 模拟直方图的形式
subroutine Exercises10_13
implicit none
integer :: errorLevel
character(len=6), dimension(7) :: arrayName ! 类名
integer, dimension(7) :: arrayValue ! 类值
arrayName = (/'100~95', '94~90 ', '89~85 ', '84~80 ', '79~75 ', '74~70 ', '69~65 '/) ! 定义类名
arrayValue = (/3, 6, 9, 7, 4, 2, 1/) ! 定义类值
write(*,*) ' Form 10.13 学生成绩分布直方图' ! 输出标题
call DrawHistogram(arrayName, arrayValue, errorLevel) ! 绘图
contains
! 直方图绘制
subroutine DrawHistogram(arrayName, arrayValue, errorLevel)
character(len=*), dimension(:), intent(in) :: arrayName ! 输入类名
integer, dimension(:), intent(in) :: arrayValue ! 输入类值
integer, intent(out) :: errorLevel ! 错误码
character(len=max(maxval(len_trim(arrayName))+1, 6)), allocatable, dimension(:, :) :: arrayDraw ! 绘图矩阵
integer :: temp, length ! 范围边界
character(len=max(maxval(len_trim(arrayName))+1, 6)) :: bar, line ! 绘制形状
integer :: i ! 循环参数
if ( size(arrayName, 1) /= size(arrayValue, 1) ) then ! 如果类名和值数量不匹配, 报错并返回
errorLevel = 1
return
end if
length = size(arrayValue, 1) ! 获取图表类数目
! temp = 1 ! 初始化类值最大值位置
! do i = 2, length ! 获取类值最大值位置
! if ( arrayValue(i) > arrayValue(temp) ) then
! temp = i
! end if
! end do
! temp = arrayValue(temp) ! 获取最大类值(话说为啥不直接用maxval函数)
temp = maxval(arrayValue) ! 获取最大类值
bar = '' ! 初始化形状
do i = 1, len(bar)-2
bar(i: i) = '%' ! 形成形状(用于表示直方图)
end do
do i = 1, len(line)
line(i: i) = '_' ! 用于显示图表下边界
end do
allocate(arrayDraw(temp+4, length+1), stat=errorLevel) ! 定义数组
if (errorLevel /= 0) print *, "arrayDraw: Allocation request denied"
arrayDraw = '' ! 初始化绘制数组
do i = 1, temp + 3
write(arrayDraw(i, 1)(1: 3), '(I3)') temp + 3 - i ! 绘制数组坐标轴纵轴值
end do
do i = 1, temp + 3
arrayDraw(i, 1)(len(bar)-1:len(bar)) = '| ' ! 绘制数组坐标轴纵轴边界
end do
arrayDraw(temp+3, 1)(len(bar)-1:len(bar)) = '|_' ! 绘制数组坐标轴零点边界
do i = temp-2, 1, -5
arrayDraw(i, 1)(len(bar)-1:len(bar)) = '|-' ! 绘制数组坐标轴纵轴刻度
end do
arrayDraw(temp+3, 2: length+1) = line ! 绘制数组坐标轴横轴
write(arrayDraw(temp+4, 2:size(arrayName, 1)+1), '(A)') (trim(arrayName(i)), i = 1, size(arrayName, 1)) ! 绘制数组坐标轴横轴类名
do i = 1, size(arrayName, 1)
arrayDraw(temp+3-arrayValue(i):temp+2, i+1) = bar ! 绘制数组直方图
end do
do i = 1, temp + 4
write(*, '(100A)') arrayDraw(i, :) ! 打印绘制数组
end do
if (allocated(arrayDraw)) deallocate(arrayDraw, stat=errorLevel) ! 释放数组
if (errorLevel /= 0) print *, "arrayDraw: Deallocation request denied"
errorLevel = 0 ! 设定错误等级为0
end subroutine DrawHistogram
end subroutine Exercises10_13
! 习题10-14 随机数直方图
module ran001
implicit none
integer :: n = 12345
end module ran001
subroutine Exercises10_14
implicit none
integer :: i
integer :: errorLevel
real :: randomValue
character(len=9), dimension(20) :: arrayName ! 类名
integer, dimension(20) :: arrayValue ! 类值
write(*,*) ' Form 10.14 随机数分布直方图' ! 输出标题
arrayName = (/&
&'0.00~0.05', '0.05~0.10', '0.10~0.15', '0.15~0.20', &
&'0.20~0.25', '0.25~0.30', '0.30~0.35', '0.35~0.40', &
&'0.40~0.45', '0.45~0.50', '0.50~0.55', '0.55~0.60', &
&'0.60~0.65', '0.65~0.70', '0.70~0.75', '0.75~0.80', &
&'0.80~0.85', '0.85~0.90', '0.90~0.95', '0.95~1.00'/) ! 定义类名
call seed0(12346.)
arrayValue = 0
do i = 1, 20000
call random(randomValue)
arrayValue(int(randomValue*20+1)) = arrayValue(int(randomValue*20+1)) + 1
end do
call DrawHistogram(arrayName, arrayValue, errorLevel) ! 绘图
contains
! 直方图绘制
subroutine DrawHistogram(arrayName, arrayValue, errorLevel)
character(len=*), dimension(:), intent(in) :: arrayName ! 输入类名
integer, dimension(:), intent(in) :: arrayValue ! 输入类值
integer, intent(out) :: errorLevel ! 错误码
character(len=max(maxval(len_trim(arrayName))+1, 7)), allocatable, dimension(:, :) :: arrayDraw ! 绘图矩阵
integer :: temp, length ! 范围边界
character(len=max(maxval(len_trim(arrayName))+1, 7)) :: bar, line ! 绘制形状
integer :: i ! 循环参数
integer :: maxValue ! 最大值
if ( size(arrayName, 1) /= size(arrayValue, 1) ) then ! 如果类名和值数量不匹配, 报错并返回
errorLevel = 1
return
end if
length = size(arrayValue, 1) ! 获取图表类数目
temp = maxval(arrayValue) ! 获取最大类值
bar = '' ! 初始化形状
do i = 1, len(bar)-2
bar(i: i) = '%' ! 形成形状(用于表示直方图)
end do
do i = 1, len(line)
line(i: i) = '_' ! 用于显示图表下边界
end do
allocate(arrayDraw(14, length+1), stat=errorLevel) ! 定义数组
if (errorLevel /= 0) print *, "arrayDraw: Allocation request denied"
arrayDraw = '' ! 初始化绘制数组
maxValue = maxval(arrayValue)
do i = 1, 13
write(arrayDraw(i, 1)(1: 4), '(I4)') nint(real(maxValue)*(13. - real(i))/10.) ! 绘制数组坐标轴纵轴值
end do
do i = 1, 12
arrayDraw(i, 1)(len(bar)-2:len(bar)) = '| ' ! 绘制数组坐标轴纵轴边界
end do
arrayDraw(13, 1)(len(bar)-2:len(bar)) = '|__' ! 绘制数组坐标轴零点边界
do i = 8, 1, -5
arrayDraw(i, 1)(len(bar)-2:len(bar)) = '|- ' ! 绘制数组坐标轴纵轴刻度
end do
arrayDraw(13, 2: length+1) = line ! 绘制数组坐标轴横轴
write(arrayDraw(14, 2:size(arrayName, 1)+1), '(A)') (trim(arrayName(i)), i = 1, size(arrayName, 1)) ! 绘制数组坐标轴横轴类名
do i = 1, size(arrayName, 1)
arrayDraw(13-nint(real(arrayValue(i))*10./real(maxValue)):12, i+1) = bar ! 绘制数组直方图
end do
do i = 1, 14
write(*, '(100A)') arrayDraw(i, :) ! 打印绘制数组
end do
if (allocated(arrayDraw)) deallocate(arrayDraw, stat=errorLevel) ! 释放数组
if (errorLevel /= 0) print *, "arrayDraw: Deallocation request denied"
errorLevel = 0 ! 设定错误等级为0
end subroutine DrawHistogram
subroutine seed0(iseed)
use ran001
real, intent(in) :: iseed
n = abs(iseed)
end subroutine seed0
subroutine random(ran)
use ran001
real, intent(inout) :: ran
n = mod(8121*n+28411,134456)
ran = real(n)/134456
end subroutine random
end subroutine Exercises10_14
! 习题10-15 拷贝文件去除注释
subroutine Exercises10_15
implicit none
character(len=132) :: str
integer :: errorLevel
open(unit=1, status='scratch', iostat=errorLevel)
if ( errorLevel /= 0 ) stop ""
write(1, '(A)') &
&"subroutine DrawHistogram(arrayName, arrayValue, errorLevel)'!'", &
&"character(len=*), dimension(:), intent(in) :: arrayName ! 输入类名", &
&"integer, dimension(:), intent(in) :: arrayValue ! 输入类值", &
&"integer, intent(out) :: errorLevel ! 错误码", &
&"character(len=max(maxval(len_trim(arrayName))+1, 7)), allocatable, dimension(:, :) :: arrayDraw ! 绘图矩阵", &
&"integer :: temp, length ! 范围边界", &
&"character(len=max(maxval(len_trim(arrayName))+1, 7)) :: bar, line ! 绘制形状"
rewind(unit=1, iostat=errorLevel)
if ( errorLevel /= 0 ) stop ""
do
read(1, '(A)', iostat=errorLevel) str
if ( errorLevel /= 0 ) exit
write(*, *) Uncomment(str)
end do
contains
function Uncomment(str)
character(len=*), intent(in) :: str
character(len=len(str)) :: Uncomment
integer :: i
integer :: runLevel
runLevel = 0
do i = 1, len(str)
if ( str(i: i) == '!' .and. (runLevel == 0) ) then ! 将感叹号转换为空格
Uncomment(i: i) = ' '
else
Uncomment(i: i) = str(i: i)
end if
if ( str(i: i) == '"' .and. runLevel == 0 ) then ! 判断不转换感叹号的场景
runLevel = 1
elseif ( str(i: i) == '"' .and. runLevel == 1 ) then
runLevel = 0
elseif ( str(i: i) == "'" .and. runLevel == 0 ) then
runLevel = 2
elseif ( str(i: i) == "'" .and. runLevel == 2 ) then
runLevel = 0
end if
end do
end function Uncomment
end subroutine Exercises10_15

398
第11章习题.f90 Normal file
View File

@ -0,0 +1,398 @@
! ==============================================================================
! 通过 gfortran ./test.f90 -o ./run && ./run 运行
! 程序名:
! 第11章习题
! 目的:
!
! 修订记录:
! 日期 编程者 改动描述
! =================== ============= =====================================
! 2021-05-13 14:32:35 Sola 习题11-5 判断格式是否正确
! 2021-05-13 15:42:31 Sola 习题11-6 函数的导数
! 2021-05-13 17:17:22 Sola 习题11-7 经时计算,判断单精度和双精度时间
! 2021-05-14 19:19:29 Sola 习题11-8 跳过习题11-9 复数计算
! 2021-05-14 19:56:11 Sola 习题11-10 复数的振幅和相位
! 2021-05-14 20:09:50 Sola 习题11-11 欧拉公式
! 程序结构:
!
! ==============================================================================
! 模块:
module Chapter11
implicit none
! 数据字典
! 声明常数
REAL, PARAMETER :: PI=3.14159265 ! PI值
REAL, PARAMETER :: e=2.718281828459 ! 自然对数
INTEGER, PARAMETER :: arrayLength=20 ! 数组基准长度
! 声明变量
! 创建显式接口
contains
! subroutine SubName(varName1,varName2)
! implicit none
! ! 数据字典
! end subroutine SubName
end module Chapter11
! ==============================================================================
! 主程序:
program ProName
implicit none
! 数据字典
! 声明常量
! 声明变量
! 变量初始化
! 数据输入
! 运算过程
! 结果输出
! call Exercises11_5
! call Exercises11_6
! call Exercises11_7
! call Exercises11_9
! call Exercises11_10
call Exercises11_11
end program ProName
! ==============================================================================
! 子程序
! subroutine SubName(varName1,varName2)
! use MouName
! implicit none
! Type, intent(inout) :: varName
! end subroutine SubName
! ==============================================================================
! 函数
! function FunName(varName1,varName2)
! use MouName
! implicit none
! end function FunName
! ==============================================================================
! 习题11-5
subroutine Exercises11_5
implicit none
call Suba
! call Subb
contains
subroutine Suba
integer, parameter :: sgl = kind(0.0)
integer, parameter :: dbl = kind(0.0D0)
real(kind=sgl) :: a
real(kind=dbl) :: b
integer :: i
integer :: errorLevel
open(unit=1, status='scratch', iostat=errorLevel)
if ( errorLevel /= 0 ) stop ""
write(*, *) sgl, dbl
do i = 1, 45
write(*, *) i, selected_real_kind(r=i)
end do
write(1, '(A)') &
&"111111111111111111111111111111111111111111111", &
&"222222222222222222222222222222222222222222222"
rewind(unit=1, iostat=errorLevel)
if ( errorLevel /= 0 ) stop ""
read(1, '(F16.2)') a, b
write(*, *) a, b
end subroutine Suba
! subroutine Subb
! end subroutine Subb
end subroutine Exercises11_5
! 习题11-6 函数的导数
subroutine Exercises11_6
implicit none
integer, parameter :: realType = selected_real_kind(p=13) ! 确认实数类型
real(realType) :: x0, dx ! 待测点, 步长
real(realType) :: derivationX0 ! 导数值
real(realType), external :: Fx ! 外部函数
x0 = 0._realType ! 变量初始化
dx = 0.01_realType
call Derivation(Fx, x0, dx, derivationX0) ! 计算导数
write(*, *) '函数在0处的值为', Fx(0._realType), '在0处的导数值为', derivationX0 ! 输出结果
contains
subroutine Derivation(inputFunction, x0, dx, derivationX0)
integer, parameter :: realType = selected_real_kind(p=13) ! 确认实数类型
real(realType), intent(in) :: x0, dx ! 输入点位及步长
real(realType), intent(out) :: derivationX0 ! 输出的导数值
real(realType), external :: inputFunction ! 外部函数
derivationX0 = (inputFunction(x0 + dx) - inputFunction(x0))/dx ! 计算导数值
end subroutine Derivation
end subroutine Exercises11_6
function Fx(x)
implicit none
integer, parameter :: realType = selected_real_kind(p=13) ! 确认实数类型
real(realType), intent(in) :: x ! 输入点位
real(realType) :: Fx ! 定义函数输出类型
Fx = 10._realType*sin(20._realType*x) ! 计算函数值
end function Fx
! 习题11-7 经时计算 不过话说回来,现在的编译器在这边好像还是有优化的,,,结果可能不太准
subroutine Exercises11_7
implicit none
integer, parameter :: dbl = selected_real_kind(p=13)
integer, parameter :: sgl = selected_real_kind(p=1)
real(dbl), dimension(10, 10) :: matrix
real(dbl), dimension(10) :: arrayX
real(sgl), dimension(10, 10) :: matrix1
real(sgl), dimension(10) :: arrayX1
integer, dimension(8) :: timeNow
real :: timePast
integer, dimension(8) :: timeOld
integer :: errorLevel
integer :: i
open(unit=1, status='scratch', iostat=errorLevel)
if ( errorLevel /= 0 ) stop ""
write(1, '(A)') &
&" -2., 5., 1., 3., 4. -1., -2., -1., -5., -2.", &
&" 6., 4., -1., 6., -4., -5., 3., -1., 4., 3.", &
&" -6., -5., -2., -2., -3., 6., 4., 2., -6., 4.", &
&" 2., 4., 4., 4., 5., -4., 0., 0., -4., 6.", &
&" -4., -1., 3., -3., -4., -4., -4., 4., 3., -3.", &
&" 4., 3., 5., 1., 1., 1., 0., 3., 3., 6.", &
&" 1., 2., -2., 0., 3., -5., 5., 0., 1., -4.", &
&" -3., -4., 2., -1., -2., 5., -1., -1., -4., 1.", &
&" 5., 5., -2., -5., 1., -4., -1., 0., -2., -3.", &
&" -5., -2., -5., 2., -1., 3., -1., 1., -4., 4."
rewind(unit=1, iostat=errorLevel)
if ( errorLevel /= 0 ) stop ""
arrayX = (/ -5., -6., -7., 0., 5., -8., 1., -4., -7., 6./)
read(1, *) (matrix(i, :), i = 1, 10)
rewind(unit=1, iostat=errorLevel)
if ( errorLevel /= 0 ) stop ""
arrayX1 = (/ -5., -6., -7., 0., 5., -8., 1., -4., -7., 6./)
read(1, *) (matrix1(i, :), i = 1, 10)
call set_timer
do i = 1, 1000000
call GAEli1(matrix1, arrayX1, errorLevel)
! arrayX1 = (/ -5., -6., -7., 0., 5., -8., 1., -4., -7., 6./)
end do
call elapsed_time(timePast)
write(*, *) '使用单精度计算消耗时间', timePast, 's'
call set_timer
do i = 1, 1000000
call GAEli2(matrix, arrayX, errorLevel)
! arrayX = (/ -5., -6., -7., 0., 5., -8., 1., -4., -7., 6./)
end do
call elapsed_time(timePast)
write(*, *) '使用双精度计算消耗时间', timePast, 's'
contains
! 解方程子程序
! 经时子程序
subroutine set_timer ! 创建子程序1
call DATE_AND_TIME(values=timeNow) ! 调用当前时间子程序
end subroutine set_timer ! 结束子程序1
subroutine elapsed_time(timePast) ! 创建子程序2
real, intent(out) :: timePast ! 定义输出变量
timeOld = timeNow ! 传递值
call set_timer ! 调用子程序1
timePast = ((real(timeNow(3)-timeOld(3))*24 + real(timeNow(5)-timeOld(5)))&
&*60 + real(timeNow(6)-timeOld(6)))*60 + real(timeNow(7)-timeOld(7)) + &
&real(timeNow(8)-timeOld(8))/1000 ! 计算经历时间(秒)
end subroutine elapsed_time ! 结束子程序2
! 高斯-亚当消元法,不破坏输入矩阵
subroutine GAEli1(matrixInput1, arrayX, errorLevel)
integer, parameter :: varKind = selected_real_kind(p=2)
real(varKind), dimension(:, :), intent(inout) :: matrixInput1 ! 输入矩阵(输入)
real(varKind), dimension(size(matrixInput1, 1), size(matrixInput1, 2)) :: matrixInput
! 运算矩阵
real(varKind), dimension(:), intent(inout) :: arrayX ! 输入常数向量, 输出X解向量
integer, intent(out) :: errorLevel ! 错误值
real(varKind) :: temp ! 临时值, 用于数值交换
integer :: maxLocate ! 最大值所在行
integer :: i, n, m ! 局部变量: 循环参数
matrixInput = matrixInput1
m = size(matrixInput, 1)
do n = 1, m
maxLocate = n ! 初始化绝对值最大的位置
do i = n+1, m ! 执行最大支点技术,减少舍入误差
if ( abs(matrixInput(i, n)) > abs(matrixInput(maxLocate, n)) ) then
maxLocate = i
end if
end do
if ( abs(matrixInput(maxLocate, n)) < 1.0E-30 ) then
errorLevel = 1 ! 如果绝对值最大为0, 则矩阵不满秩, 无解
return ! 退出运算
end if
if ( maxLocate /= n ) then ! 如果绝对值最大值位置发生了变化, 则交换
do i = 1, m
temp = matrixInput(maxLocate, i)
matrixInput(maxLocate, i) = matrixInput(n, i)
matrixInput(n, i) = temp
end do
temp = arrayX(maxLocate)
arrayX(maxLocate) = arrayX(n)
arrayX(n) = temp
end if
do i = 1, m ! 消去其他行所有第n列的系数
if ( i /= n ) then
temp = -matrixInput(i, n)/matrixInput(n, n) ! 这里务必要设置一个临时值保存数值, 不然会被修改
matrixInput(i, :) = matrixInput(i, :) + matrixInput(n, :)*temp
arrayX(i) = arrayX(i) + arrayX(n)*temp
end if
end do
end do
do i = 1, m ! 产生X的解向量
arrayX(i) = arrayX(i)/matrixInput(i, i)
matrixInput(i, i) = 1.
end do
errorLevel = 0
end subroutine GAEli1
subroutine GAEli2(matrixInput1, arrayX, errorLevel)
integer, parameter :: varKind = selected_real_kind(p=13)
real(varKind), dimension(:, :), intent(inout) :: matrixInput1 ! 输入矩阵(输入)
real(varKind), dimension(size(matrixInput1, 1), size(matrixInput1, 2)) :: matrixInput
! 运算矩阵
real(varKind), dimension(:), intent(inout) :: arrayX ! 输入常数向量, 输出X解向量
integer, intent(out) :: errorLevel ! 错误值
real(varKind) :: temp ! 临时值, 用于数值交换
integer :: maxLocate ! 最大值所在行
integer :: i, n, m ! 局部变量: 循环参数
matrixInput = matrixInput1
m = size(matrixInput, 1)
do n = 1, m
maxLocate = n ! 初始化绝对值最大的位置
do i = n+1, m ! 执行最大支点技术,减少舍入误差
if ( abs(matrixInput(i, n)) > abs(matrixInput(maxLocate, n)) ) then
maxLocate = i
end if
end do
if ( abs(matrixInput(maxLocate, n)) < 1.0E-30 ) then
errorLevel = 1 ! 如果绝对值最大为0, 则矩阵不满秩, 无解
return ! 退出运算
end if
if ( maxLocate /= n ) then ! 如果绝对值最大值位置发生了变化, 则交换
do i = 1, m
temp = matrixInput(maxLocate, i)
matrixInput(maxLocate, i) = matrixInput(n, i)
matrixInput(n, i) = temp
end do
temp = arrayX(maxLocate)
arrayX(maxLocate) = arrayX(n)
arrayX(n) = temp
end if
do i = 1, m ! 消去其他行所有第n列的系数
if ( i /= n ) then
temp = -matrixInput(i, n)/matrixInput(n, n) ! 这里务必要设置一个临时值保存数值, 不然会被修改
matrixInput(i, :) = matrixInput(i, :) + matrixInput(n, :)*temp
arrayX(i) = arrayX(i) + arrayX(n)*temp
end if
end do
end do
do i = 1, m ! 产生X的解向量
arrayX(i) = arrayX(i)/matrixInput(i, i)
matrixInput(i, i) = 1.
end do
errorLevel = 0
end subroutine GAEli2
end subroutine Exercises11_7
! 习题11-9 复数计算
subroutine Exercises11_9
implicit none
integer, parameter :: dbl = selected_real_kind(p=3)
complex(dbl), dimension(3, 3) :: matrix
complex(dbl), dimension(3) :: arrayX
integer :: errorLevel
integer :: i
open(unit=1, status='scratch', iostat=errorLevel)
if ( errorLevel /= 0 ) stop ""
write(1, '(A)') &
&"( -2., 5.), ( 1., 3.), ( 4., -1.)", &
&"( 2., -1.), ( -5., -2.), ( -1., 6.)", &
&"( -1., 6.), ( -4., -5.), ( 3., -1.)", &
&"( 7., 5.), (-10., -8.), ( -3., -3.)"
rewind(unit=1, iostat=errorLevel)
if ( errorLevel /= 0 ) stop ""
read(1, *) (matrix(i, :), i = 1, 3)
read(1, *) arrayX
call GAEli(matrix, arrayX, errorLevel)
write(*, *) '计算结果为:'
write(*, *) 'x1 = ', arrayX(1)
write(*, *) 'x2 = ', arrayX(2)
write(*, *) 'x3 = ', arrayX(3)
contains
! 复数求解
subroutine GAEli(matrixInput1, arrayX, errorLevel)
integer, parameter :: varKind = selected_real_kind(p=3)
complex(varKind), dimension(:, :), intent(inout) :: matrixInput1 ! 输入矩阵(输入)
complex(varKind), dimension(size(matrixInput1, 1), size(matrixInput1, 2)) :: matrixInput
! 运算矩阵
complex(varKind), dimension(:), intent(inout) :: arrayX ! 输入常数向量, 输出X解向量
integer, intent(out) :: errorLevel ! 错误值
complex(varKind) :: temp ! 临时值, 用于数值交换
integer :: maxLocate ! 最大值所在行
integer :: i, n, m ! 局部变量: 循环参数
matrixInput = matrixInput1
m = size(matrixInput, 1)
do n = 1, m
maxLocate = n ! 初始化绝对值最大的位置
do i = n+1, m ! 执行最大支点技术,减少舍入误差
if ( cabs(matrixInput(i, n)) > cabs(matrixInput(maxLocate, n)) ) then
maxLocate = i
end if
end do
if ( cabs(matrixInput(maxLocate, n)) < 1.0E-30 ) then
errorLevel = 1 ! 如果绝对值最大为0, 则矩阵不满秩, 无解
return ! 退出运算
end if
if ( maxLocate /= n ) then ! 如果绝对值最大值位置发生了变化, 则交换
do i = 1, m
temp = matrixInput(maxLocate, i)
matrixInput(maxLocate, i) = matrixInput(n, i)
matrixInput(n, i) = temp
end do
temp = arrayX(maxLocate)
arrayX(maxLocate) = arrayX(n)
arrayX(n) = temp
end if
do i = 1, m ! 消去其他行所有第n列的系数
if ( i /= n ) then
temp = -matrixInput(i, n)/matrixInput(n, n) ! 这里务必要设置一个临时值保存数值, 不然会被修改
matrixInput(i, :) = matrixInput(i, :) + matrixInput(n, :)*temp
arrayX(i) = arrayX(i) + arrayX(n)*temp
end if
end do
end do
do i = 1, m ! 产生X的解向量
arrayX(i) = arrayX(i)/matrixInput(i, i)
matrixInput(i, i) = 1.
end do
errorLevel = 0
end subroutine GAEli
end subroutine Exercises11_9
! 习题11-10 复数的振幅和相位
subroutine Exercises11_10
implicit none
integer, parameter :: sgl=selected_real_kind(p=2) ! 定义单精度
complex(sgl) :: var1 ! 定义复数
real(sgl) :: amp, theta ! 定义振幅和相位
real(sgl), parameter :: PI=3.14159265 ! 圆周率
call InputComplex(amp, theta) ! 调用子程序, 获取输入复数的振幅和相位
write(*, *) '振幅为:', amp, ' 相位为:', theta, '°' ! 输出结果
contains
subroutine InputComplex(amp, theta)
integer, parameter :: sgl=selected_real_kind(p=2) ! 定义单精度
real(sgl), intent(out) :: amp, theta ! 定义输出结果
complex(sgl) :: var1 ! 定义输入复数
write(*, *) '请输入一个复数:' ! 提示信息
read(*, *) var1 ! 读取输入复数
amp = cabs(var1) ! 获取振幅
theta = atan(aimag(var1)/real(var1))*360./(2.*PI) ! 获取相位(角度)
end subroutine InputComplex
end subroutine Exercises11_10
! 习题11-11 欧拉公式
subroutine Exercises11_11
implicit none
integer, parameter :: sgl=selected_real_kind(p=2) ! 定义单精度
real(sgl) :: theta ! 定义角度(弧度)
complex(sgl) :: var1 ! 定义复数
real(sgl) :: PI=3.14159265 ! 圆周率
integer :: i ! 循环参数
do i = 0, 2 ! 循环theta = 0, pi/2, pi
theta = i*PI/2. ! 计算theta
write(*, '("theta = ", F6.2,", e^theta_i = " 2("(", ES9.2, ",", ES9.2, ") "))') &
&theta, cexp(cmplx(0., theta, sgl)), EulerFormula(theta)! 输出结果
end do
contains
! 欧拉公式
function EulerFormula(theta)
integer, parameter :: sgl=selected_real_kind(p=2) ! 定义单精度
real(sgl), intent(in) :: theta ! 定义输入角度(弧度)
complex(sgl) :: EulerFormula ! 定义函数返回类型
EulerFormula = cmplx(cos(theta), sin(theta), sgl) ! 计算返回值
end function EulerFormula
end subroutine Exercises11_11

298
第12章习题.f90 Normal file
View File

@ -0,0 +1,298 @@
! ==============================================================================
! 通过 gfortran ./test.f90 -o ./run && ./run 运行
! 程序名:
! 第12章习题
! 目的:
!
! 修订记录:
! 日期 编程者 改动描述
! =================== ============= =====================================
! 2021-05-16 16:04:01 Sola 习题12-1 改进例题程序
! 2021-05-16 20:45:49 Sola 习题12-2 复数坐标系转换
! 2021-05-16 20:46:28 Sola 习题12-3 复数极坐标乘法
! 2021-05-16 20:46:40 Sola 习题12-4 复数极坐标除法
! 2021-05-16 20:56:15 Sola 习题12-5 建立过了,跳过
! 2021-05-16 20:59:10 Sola 习题12-6 卡笛尔坐标系下点位和直线
! 2021-05-16 21:04:08 Sola 习题12-7 两点间距离
! 2021-05-16 21:14:41 Sola 习题12-8 通过两点计算直线参数
! 2021-05-16 21:36:52 Sola 习题12-9 追踪雷达目标,莫得数据,跳过
! 程序结构:
!
! ==============================================================================
! 模块:
module Chapter12
implicit none
! 数据字典
! 声明常数
REAL, PARAMETER :: PI=3.14159265 ! PI值
REAL, PARAMETER :: e=2.718281828459 ! 自然对数
INTEGER, PARAMETER :: arrayLength=20 ! 数组基准长度
integer, parameter :: sgl = selected_real_kind(p=1) ! 单精度类型
type :: complexChange
real(sgl) :: var1 ! 参数1
real(sgl) :: var2 ! 参数2
contains
procedure, pass :: Car2Pol ! 直角坐标系转化为极坐标系
procedure, pass :: Pol2Car ! 极坐标系转化为直角坐标系
procedure, pass :: PolProduct ! 极坐标系乘法
procedure, pass :: PolDivision ! 极坐标系乘法
end type complexChange
type :: point ! 点位的派生数据
real(sgl) :: x ! X坐标
real(sgl) :: y ! Y坐标
contains
procedure, pass :: Distance ! 两点间距离
procedure, pass :: Point2line ! 计算两点间直线方程
end type point
type :: line ! 直线的派生数据
real(sgl) :: m ! 斜率
real(sgl) :: b ! 截距
end type line
type :: radarInfo
real(sgl) :: length ! 距离
real(sgl) :: theta ! 角度
real(sgl) :: time ! 扫描时间
end type radarInfo
! 声明变量
! 创建显式接口
contains
! subroutine SubName(varName1,varName2)
! implicit none
! ! 数据字典
! end subroutine SubName
! 直角坐标系转化为极坐标系
type(complexChange) function Car2Pol(this)
class(complexChange) :: this
Car2Pol%var1 = sqrt(this%var1**2 + this%var2**2)
Car2Pol%var2 = atan(this%var2, this%var1)
end function Car2Pol
! 极坐标系转化为直角坐标系
type(complexChange) function Pol2Car(this)
class(complexChange) :: this
Pol2Car%var1 = this%var1*cos(this%var2)
Pol2Car%var2 = this%var1*sin(this%var2)
end function Pol2Car
! 复数的极坐标系乘法
type(complexChange) function PolProduct(this, input)
class(complexChange) :: this, input
PolProduct%var1 = this%var1*input%var1
PolProduct%var2 = mod(this%var2 + input%var2 + PI, 2*PI) - PI
end function PolProduct
! 复数的极坐标除法
type(complexChange) function PolDivision(this, input)
class(complexChange) :: this, input
PolDivision%var1 = this%var1/input%var1
PolDivision%var2 = mod(this%var2 - input%var2 + PI, 2*PI) - PI
end function PolDivision
! 计算两点间距离
real function Distance(pointA, pointB)
class(point) :: pointA, pointB
Distance = sqrt((pointB%x - pointA%x)**2 + (pointB%y - pointA%y)**2)
end function Distance
type(line) function Point2line(pointA, pointB)
class(point) :: pointA, pointB
if ( abs(pointA%x - pointB%x) < 1E-30 ) then
stop "所求直线无斜率与Y轴平行"
end if
Point2line%m = (pointA%y - pointB%y)/(pointA%x - pointB%x)
Point2line%b = pointA%y - Point2line%m*pointA%x
end function Point2line
end module Chapter12
! ==============================================================================
! 主程序:
program ProName
implicit none
! 数据字典
! 声明常量
! 声明变量
! 变量初始化
! 数据输入
! 运算过程
! 结果输出
! call customer_database
! call Exercises12_2
! call Exercises12_7
end program ProName
! ==============================================================================
! 子程序
! subroutine SubName(varName1,varName2)
! use MouName
! implicit none
! Type, intent(inout) :: varName
! end subroutine SubName
! ==============================================================================
! 函数
! function FunName(varName1,varName2)
! use MouName
! implicit none
! end function FunName
! ==============================================================================
! 习题12-1 修改例题
! 定义了公共模块用来读取数据
module types
implicit none
type :: presonal_info
character(len=12) :: first
character :: mi
character(len=12) :: last
character(len=26) :: street
character(len=12) :: city
character(len=2) :: state
integer :: zip
end type presonal_info
end module types
! 输入数据以及排序的主函数
subroutine customer_database
use types
implicit none
integer, parameter :: MAX_SIZE = 100
logical, external :: lt_last
logical, external :: lt_city
logical, external :: lt_zip
type(presonal_info), dimension(MAX_SIZE) :: customers
integer :: choice
logical :: exceed = .FALSE.
character(len=20) :: filename
integer :: i
integer :: nvals = 0
integer :: status
type(presonal_info) :: temp
open(unit=1, status='scratch', iostat=status)
if ( status /= 0 ) stop ""
write(1, '(A)') &
&"John Q Public 123 Sesame Street Anywhere NY 10035", &
&"James R Johnson Rt. 5 Box 207C West Monroe LA 71291", &
&"Joseph P Ziskend P. O. Box 433 APO AP 96555", &
&"Andrew D Jackson Jackson Square New Orleans LA 70003", &
&"Jane X Doe 12 Lakeside Drive Glenview IL 60025", &
&"Colin A Jeffries 11 Main Street Chicago IL 60003"
rewind(unit=1, iostat=status)
if ( status /= 0 ) stop ""
do
read(1, 1010, iostat=status) temp
1010 format(A12, 1X, A1, 1X, A12, 1X, A26, 1X, A12, 1X, A2, 1X, I5)
if ( status /= 0 ) exit
nvals = nvals + 1
if ( nvals <= MAX_SIZE ) then
customers(nvals) = temp
else
exceed = .TRUE.
end if
end do
if ( exceed ) then
write(*, 1020) nvals, MAX_SIZE
1020 format(' Maximum array size exceeded: ', I6, ' > ', I6)
else
write(*, 1030)
1030 format(&
1X, 'Enter way to sort database:', /&
1X, ' 1 -- By last name ', /&
1X, ' 2 -- By city ', /&
1X, ' 3 -- By zip code ')
read(*, *) choice
select case (choice)
case(1)
call sort_database(customers, nvals, lt_last)
case(2)
call sort_database(customers, nvals, lt_city)
case(3)
call sort_database(customers, nvals, lt_zip)
case default
write(*, *) 'Invalid choice entered!'
end select
write(*, '(A)') 'The sorted database values are: '
write(*, 1040) (customers(i), i = 1, nvals)
1040 format(A12, 1X, A1, 1X, A12, 1X, A26, 1X, A12, 1X, A2, 1X, I5)
end if
end subroutine customer_database
! 排序对应数据子程序
subroutine sort_database(array, n, lt_fun)
use types
implicit none
integer, intent(in) :: n
type(presonal_info), dimension(n), intent(inout) :: array
logical, external :: lt_fun
integer :: i
integer :: iptr
integer :: j
type(presonal_info) :: temp
do i = 1, n-1
iptr = i
do j = i+1, n
if ( lt_fun(array(j),array(iptr)) ) then
iptr = j
end if
end do
if ( i /= iptr ) then
temp = array(i)
array(i) = array(iptr)
array(iptr) = temp
end if
end do
end subroutine sort_database
! 排序函数
logical function lt_last(a, b)
use types
implicit none
type(presonal_info), intent(in) :: a, b
lt_last = LLT(a%last, b%last)
end function lt_last
! 主要在这里修改,全部检测大写即可,如果需要继续改进的话,名称可能也要改?倒是也没必要,名字只有首字母大写
logical function lt_city(a, b)
use types
implicit none
type(presonal_info), intent(in) :: a, b
lt_city = LLT(Ucase(a%city), Ucase(b%city))
contains
function Ucase(str)
character(len=*), intent(in) :: str ! 定义输入字符串
character(len=len(str)) :: ucase ! 定义函数类型
integer :: i ! 循环参数
do i = 1, len(str) ! 对输入每个字符循环
if ( lge(str(i: i), 'a') .and. lle(str(i: i), 'z') ) then ! 如果字符在a~z中
Ucase(i: i) = achar( iachar(str(i: i)) - 32 ) ! 输出大写
else
Ucase(i: i) = str(i: i) ! 如果不在, 输出原字符
end if
end do
end function Ucase
end function lt_city
logical function lt_zip(a, b)
use types
implicit none
type(presonal_info), intent(in) :: a, b
lt_zip = a%zip < b%zip
end function lt_zip
! 习题12-2 具体函数参考派生数据在模块中的定义
! 习题12-3 极坐标表示复数乘法
! 习题12-4 极坐标表示复数出发
subroutine Exercises12_2
use Chapter12
implicit none
type(complexChange) :: POLAR, a, b
! 习题12-2
POLAR = complexChange(123., 456.)
write(*, *) 'POLAR为 ', POLAR
write(*, *) 'POLAR转化为极坐标系为 ', POLAR%Car2Pol()
write(*, *) 'POLAR转化为直角坐标系为 ', POLAR%Pol2Car()
! 习题12-3
POLAR = POLAR%Car2Pol()
a = POLAR
b = POLAR%PolProduct(a)
write(*, *) 'POLAR之间的乘积为 ', b
! 习题12-4
b = b%PolDivision(a)
write(*, *) '其乘积除以POLAR为 ', b
contains
end subroutine Exercises12_2
! 习题12-7 两点间距离,两点间建立直线
subroutine Exercises12_7
use Chapter12
implicit none
type(point) :: pointA, pointB
pointA = point(1., 3.)
pointB = point(3., 1.)
write(*, *) '点A与点B之间的距离为 ', pointA%Distance(pointB)
write(*, *) '点A与点B之间的直线的斜率和截距为 ', pointA%Point2line(pointB)
contains
end subroutine Exercises12_7

208
第13章习题.f90 Normal file
View File

@ -0,0 +1,208 @@
! ==============================================================================
! 通过 gfortran ./test.f90 -o ./run && ./run 运行
! 程序名:
! 第13章习题
! 目的:
!
! 修订记录:
! 日期 编程者 改动描述
! =================== ============= =====================================
! 2021-05-19 21:36:27 Sola 习题13-1 上一章写过了
! 2021-05-19 21:36:44 Sola 习题13-2 递归函数和子程序计算阶乘
! 2021-05-19 22:06:42 Sola 习题13-3 验证例题13-2的子程序
! 2021-05-19 22:30:37 Sola 习题13-4 ~ 习题13-18 跳过
! 2021-05-19 22:56:02 Sola 习题13-19 极坐标复数
! 2021-05-19 23:21:36 Sola 习题13-20 复数的极坐标乘除
! 2021-05-19 23:40:41 Sola 习题13-21 ~ 习题13-22 跳过
! 2021-05-19 23:42:15 Sola 习题13-23 ...之前就是这么写的
! 2021-05-19 23:44:46 Sola 习题13-24 跳过
! 程序结构:
!
! ==============================================================================
! 主程序:
program Chapter13
implicit none
! 数据字典
! 声明常量
! 声明变量
! 变量初始化
! 数据输入
! 运算过程
! 结果输出
! call Exercises13_2
! call Exercises13_3
! call Exercises13_19
! call Exercises13_20
end program Chapter13
! ==============================================================================
! 习题13-2 递归函数和子程序计算阶乘
subroutine Exercises13_2
implicit none
interface
subroutine SubFactorial(n, result)
implicit none
integer, intent(in) :: n
integer, intent(out) :: result
integer :: temp
end subroutine SubFactorial
recursive function FunFactorial(n) result(result)
implicit none
integer, intent(in) :: n
integer :: result
end function FunFactorial
end interface
integer :: result
call SubFactorial(5, result)
write(*, *) "通过子程序计算5的阶乘为 ", result
write(*, *) "通过函数计算10的阶乘为 ", FunFactorial(10)
end subroutine Exercises13_2
! 阶乘运算子程序
recursive subroutine SubFactorial(n, result)
implicit none
integer, intent(in) :: n
integer, intent(out) :: result
integer :: temp
if ( n >= 1 ) then
call SubFactorial(n-1, temp)
result = n*temp
else
result = 1
end if
end subroutine SubFactorial
! 阶乘运算函数
recursive function FunFactorial(n) result(result)
implicit none
integer, intent(in) :: n
integer :: result
if ( n >= 1 ) then
result = n*FunFactorial(n-1)
else
result = 1
end if
end function FunFactorial
! 习题13-3 验证例题13-2子程序, 求极值
subroutine Exercises13_3
implicit none
interface
subroutine Extremes(a, n, maxVal, posMaxVal, minVal, posMinVal)
implicit none
integer, intent(in) :: n
real, intent(in), dimension(n) :: a
real, intent(out), optional :: maxVal
integer, intent(out), optional :: posMaxVal
real, intent(out), optional :: minVal
integer, intent(out), optional :: posMinVal
end subroutine Extremes
end interface
real, dimension(18) :: input
integer :: maxLoc, minLoc
real :: maxValue, minValue
input = (/ 3., 4., 0., 1., 2., 1., 1., 9., 9., 8., 0., 7., 2., 0., 7., 3., 3., 3./)
call Extremes(input, 18, minVal=minValue, maxVal=maxValue, posMinVal=minLoc, posMaxVal=maxLoc)
write(*, *) "数组在第", maxLoc, "位取到最大值", maxValue
write(*, *) "数组在第", minLoc, "位取到最小值", minValue
end subroutine Exercises13_3
subroutine Extremes(a, n, maxVal, posMaxVal, minVal, posMinVal)
implicit none
integer, intent(in) :: n
real, intent(in), dimension(n) :: a
real, intent(out), optional :: maxVal
integer, intent(out), optional :: posMaxVal
real, intent(out), optional :: minVal
integer, intent(out), optional :: posMinVal
integer :: i
real :: realMax
integer :: posMax
real :: realMin
integer :: posMin
realMax = a(1)
posMax = 1
realMin = a(1)
posMin = 1
do i = 2, n
if ( a(i) > realMax ) then
realMax = a(i)
posMax = i
end if
if ( a(i) < realMin ) then
realMin = a(i)
posMin = i
end if
end do
if ( present(maxVal) ) maxVal = realMax
if ( present(posMaxVal) ) posMaxVal = posMax
if ( present(minVal) ) minVal = realMin
if ( present(posMinVal) ) posMinVal = posMin
end subroutine Extremes
! 习题13-19 极坐标复数
module Exercises13_19_Mod
implicit none
interface assignment(=)
module procedure Complex2Polar
module procedure Polar2Complex
end interface
interface operator(*)
module procedure PolarMul
end interface
interface operator(/)
module procedure PolarDiv
end interface
type :: polar
real :: z
real :: theta
end type
private
! private :: Complex2Polar, Polar2Complex
public :: assignment(=), polar, operator(*), operator(/)
contains
subroutine Complex2Polar(result, input)
implicit none
type(polar), intent(out) :: result
complex, intent(in) :: input
result%z = cabs(input)
result%theta = atan(aimag(input)/real(input))
end subroutine
subroutine Polar2Complex(result, input)
implicit none
complex, intent(out) :: result
type(polar), intent(in) :: input
result = cmplx(input%z*cos(input%theta), input%z*sin(input%theta))
end subroutine
function PolarMul(var1, var2) result(result)
implicit none
type(polar), intent(in) :: var1, var2
type(polar) :: result
result%z = var1%z*var2%z
result%theta = mod(var1%theta + var2%theta + 3.141593, 3.141593*2) - 3.141593
end function PolarMul
function PolarDiv(var1, var2) result(result)
implicit none
type(polar), intent(in) :: var1, var2
type(polar) :: result
result%z = var1%z/var2%z
result%theta = mod(var1%theta - var2%theta + 3.141593, 3.141593*2) - 3.141593
end function PolarDiv
end module Exercises13_19_Mod
subroutine Exercises13_19
use Exercises13_19_Mod, only: assignment(=), polar
implicit none
type(polar) :: a
complex :: b
b = (1.0, 2.0)
a = b
b = a
write(*, *) "计算得到的极坐标形式为", a, "; 计算得到的直角坐标形式为", b
end subroutine Exercises13_19
! 习题13-20 复数的极坐标乘除
subroutine Exercises13_20
use Exercises13_19_Mod, only: polar, operator(*), operator(/), assignment(=)
implicit none
complex :: a, b
type(polar) :: c, d
a = (1.0, 1.0)
b = (1.0,-1.0)
c = a
d = b
write(*, *) "c的初始值为: ", c, "; d的初始值为: ", d
write(*, *) "c*d的结果为: ", c*d, "; c/d的结果为: ", c/d
end subroutine Exercises13_20

500
第14章习题.f90 Normal file
View File

@ -0,0 +1,500 @@
! ==============================================================================
! 通过 gfortran ./test.f90 -o ./run && ./run 运行
! 程序名:
! 第14章习题
! 目的:
!
! 修订记录:
! 日期 编程者 改动描述
! =================== ============= =====================================
! 2021-05-20 22:06:14 Sola 测验14-1 格式描述符的使用
! 2021-05-22 00:53:01 Sola 测验14-2 跳过,顺便判断正误全错
! 2021-05-22 16:36:07 Sola 习题14-1 ~ 习题14-3 跳过
! 2021-05-22 16:36:28 Sola 习题14-4 整数描述符
! 2021-05-22 16:39:34 Sola 习题14-5 使用其他进制描述符
! 2021-05-22 16:52:07 Sola 习题14-6 使用通用类型显示随机数
! 2021-05-22 16:58:00 Sola 习题14-7 使用:描述符
! 2021-05-22 17:36:35 Sola 习题14-8 使用通用类型描述符
! 2021-05-22 17:41:53 Sola 习题14-9 工程表示法
! 2021-05-22 17:45:23 Sola 习题14-10 跳过
! 2021-05-22 17:45:32 Sola 习题14-11 验证列表输出
! 2021-05-22 19:05:42 Sola 习题14-12 验证列表读取
! 2021-05-22 19:36:08 Sola 习题14-13 跳过
! 2021-05-22 19:36:17 Sola 习题14-14 验证不同类型输出
! 2021-05-22 19:55:46 Sola 习题14-15 ~ 习题14-17 跳过
! 2021-05-22 19:56:16 Sola 习题14-18 截尾拷贝文件
! 2021-05-23 13:14:29 Sola 习题14-19 INQUIRE语句测试等
! 2021-05-23 14:00:38 Sola 习题14-20 逆置方式复制文件
! 2021-05-23 14:40:18 Sola 习题14-21 比较格式化和未格式化文件
! 2021-05-23 15:47:44 Sola 习题14-22 比较顺序和直接访问文件
! 程序结构:
!
! ==============================================================================
! 主程序:
program Chapter14
implicit none
! 数据字典
! 声明常量
! 声明变量
! 变量初始化
! 数据输入
! 运算过程
! 结果输出
! call Test14_1
call Exercises14_4
! call Exercises14_6
! call Exercises14_7
! call Exercises14_8
! call Exercises14_11
! call Exercises14_14
! call Exercises14_18
! call Exercises14_19
! call Exercises14_20
! call Exercises14_21
call Exercises14_22
end program Chapter14
! ==============================================================================
subroutine Test14_1
implicit none
real :: a=4096.07
integer :: i=-2002, j=1776, k=-3
write(*, 1) a, a, a, a, a
1 format(1X, F10.1, F9.2, E12.5, G12.5, G11.4)
read(*, *) i, j, k
write(*, 2) i, j, k
2 format(' i = ', I10, ' j = ', I10, ' k = ', I10)
! write(*, '(I8, I8.8)') 1024, 1024
end subroutine Test14_1
! 习题14-4 整数描述符 习题14-5 使用其他进制描述符
subroutine Exercises14_4
implicit none
integer :: i
write(*, *) 'print I8 & I8.8'
write(*, 1) 1024, 1024, -128, -128, 30000, 30000
1 format(I8, 2X, I8.8)
write(*, *) 'print B16, O11 & Z8'
write(*, 2) (1024, i = 1, 3), (-128, i = 1, 3), (30000, i = 1, 3)
2 format(B16, T20, O11, T40, Z8)
end subroutine Exercises14_4
! 习题14-6 使用万能类型显示随机数
subroutine Exercises14_6
implicit none
real :: temp
integer :: i
do i = 1, 9
call random_seed()
call random_number(temp)
temp = temp*110000 - 10000
write(*, '(I1, 2X, G11.5)') i, temp
end do
end subroutine Exercises14_6
! 习题14-7 使用:描述符
subroutine Exercises14_7
implicit none
real, dimension(9) :: temp
integer :: i
do i = 1, 9
! call random_seed()
call random_number(temp(i))
temp(i) = temp(i)*110000 - 10000
end do
! write(*, '(2("VALUE(", SSI1, ") = ", SPF10.2:, 2X))') (i, temp(i), i = 1, 9)
write(*, '(2("VALUE(", SSI1, ") = ", SPI7.6, SSF0.2:, 2X))') (i, int(temp(i)), abs(temp(i)-int(temp(i))), i = 1, 9)
end subroutine Exercises14_7
! 习题14-8 使用通用类型描述符 习题14-9 工程表示法
subroutine Exercises14_8
implicit none
! 习题14-8 使用通用类型描述符
write(*, '(G10.4)') -6.38765E10
write(*, '(G10.4)') -6.38765E2
write(*, '(G10.4)') -6.38765E-1
write(*, '(G10.4)') 2345.6
write(*, '(G10.4)') .TRUE.
write(*, '(G10.4)') 'String!'
! 习题14-9 工程表示法
write(*, '(EN15.6)') -6.38765E10
write(*, '(EN15.6)') -6.38765E2
write(*, '(EN15.6)') -6.38765E-1
write(*, '(EN15.6)') 2345.6
end subroutine Exercises14_8
! 习题14-11 验证列表输出
! 习题14-12 验证列表读取
subroutine Exercises14_11
implicit none
integer :: i, j
real, dimension(3, 3) ::array
integer :: errorLevel
namelist /io/ array
array = reshape((/((10.*i*j, j = 1, 3), i = 0, 2)/), (/3, 3/))
write(*, *) "习题14-11 验证列表输出"
write(*, nml=io)
open(unit=1, status='scratch', iostat=errorLevel)
if ( errorLevel /= 0 ) stop ""
write(1, '(A)') &
&"&io array(1, 1) = -100.", &
&"array(3, 1) = 6., array(1, 3) = -6./", &
&"array(2, 2) = 1000. /"
rewind(unit=1, iostat=errorLevel)
if ( errorLevel /= 0 ) stop ""
read(1, nml=io)
write(*, *) "习题14-12 验证列表读取"
write(*, nml=io)
end subroutine Exercises14_11
! 习题14-14 验证不同类型输出
subroutine Exercises14_14
implicit none
call SubA
call SubB
contains
subroutine SubA
implicit none
real :: value=356.248
integer :: i
write(*, 200) 'Value = ', (value, i = 1, 5)
200 format('0', A, F10.4, G10.2, G11.5, G11.6, ES10.3)
end subroutine SubA
subroutine SubB
implicit none
integer, dimension(5) :: i
integer :: j
do j = 1, 5
i(j) = j**2
end do
read(*, *) i
write(*, 500) i
500 format(3(10X, I5))
end subroutine SubB
end subroutine Exercises14_14
! 习题14-18 截尾拷贝文件
! 1. 在OPEN语句中使用STATUS=和IOSTAT=子句确认输入文件已经存在
! 2. 在OPEN语句中使用STATUS=和IOSTAT=子句确认输出文件不存在
! 3. 如果输出文件存在,提示用户是否覆盖,否则终止程序
! 4. 拷贝完成后,询问用户是否删除原文件
! 变量:输入文件名、输出文件名、拷贝临时变量、错误状态值
subroutine Exercises14_18
implicit none
character(len=128) :: inputFile, outputFile ! 输入输出文件名
integer :: errorLevel ! 错误状态码
character(len=200) :: temp ! 保存输入的临时变量
character :: overwriteSwitch ! 判断是否覆盖已存在的输出文件的变量
logical :: outputFileOpen ! 判断输出文件是否打开的变量
do ! 获取输入文件名
write(*, fmt='(A)', advance='no') 'Please enter the name of the input file : ' ! 提示输入输入文件名
read(*, *) inputFile ! 读取输入文件名
open(unit=1, status='old', iostat=errorLevel, file=inputFile) ! 打开输入文件
if ( errorLevel /= 0 ) then
write(*, *) 'Warning: The input file dont exist!' ! 如果输入文件不存在, 提示错误并重新输入
else
exit ! 如果输入文件存在, 进行下一环节
end if
end do
write(*, fmt='(A)', advance='no') 'Please enter the name of the output file : ' ! 提示输入输出文件名
read(*, *) outputFile ! 读取输出文件名
open(unit=2, status='new', iostat=errorLevel, file=outputFile) ! 以新文件形式打开输出文件
if ( errorLevel /= 0 ) then
write(*, fmt='(A)', advance='no') 'Warning: The output file has existed, overwrite it? (Y/N): ' ! 如果输出文件存在, 提示是否覆盖
do
read(*, *, iostat=errorLevel) overwriteSwitch ! 读取用户选项
if ( errorLevel /= 0 .or. ( Ucase(overwriteSwitch) /= 'Y' .and. Ucase(overwriteSwitch) /= 'N' ) ) then ! 如果输入非法
write(*, fmt='(A)', advance='no') 'Illgle input, please enter again (Y/N): ' ! 提示错误, 并再次读取用户输入
elseif ( Ucase(overwriteSwitch) == 'Y' ) then
open(unit=2, status='replace', iostat=errorLevel, file=outputFile) ! 如果选择覆盖
if ( errorLevel /= 0 ) stop "Warning: Replace the output file fatal!" ! 如果打开输出文件失败, 退出程序
exit ! 如果打开输出文件成功, 进行下一环节
else
exit ! 如果选择不覆盖, 进入下一环节
end if
end do
end if
if ( Ucase(overwriteSwitch) /= 'N' ) then ! 如果输出文件不存在或用户选择覆盖
inquire(unit=2, opened=outputFileOpen, iostat=errorLevel) ! 确认输出文件已打开
if ( errorLevel /= 0 ) stop "Query output file status error " ! 如果查询输出文件状态出错, 提示错误信息并终止程序
if ( outputFileOpen .eqv. .FALSE. ) stop "The output file is not open!" ! 如果输出文件未打开, 提示错误信息并终止程序
do ! 逐行复制文件内容
read(1, '(A)', iostat=errorLevel) temp ! 读取每行给临时变量
if ( errorLevel < 0 ) then
exit ! 如果到达文件末尾, 结束读取, 进入下一环节
elseif ( errorLevel > 0 ) then
stop "Error reading file record!" ! 如果读取文件记录出错, 提示错误信息并终止程序
else
write(2, '(A)', iostat=errorLevel) trim(temp) ! 将读取到的内容去除尾部空格后, 输出到输出文件
! write(*, '(A)', iostat=errorLevel) trim(temp)
if ( errorLevel /= 0 ) stop "Error copying records!" ! 拷贝记录出错, 提示错误信息并终止程序
end if
end do
write(*, fmt='(A)', advance='no') 'The copy is complete, whether to delete the input file? (Y/N): ' ! 复制文件完成, 提示用户是否删除输入文件
do ! 检测用户输出
read(*, *, iostat=errorLevel) overwriteSwitch ! 读取用户输出(这里重复使用变量了,,,)
if ( errorLevel /= 0 .or. ( Ucase(overwriteSwitch) /= 'Y' .and. Ucase(overwriteSwitch) /= 'N' ) ) then
write(*, fmt='(A)', advance='no') 'Illgle input, please enter again (Y/N): ' ! 如果输入非法, 提示错误信息并重新读取用户输入
elseif ( Ucase(overwriteSwitch) == 'Y' ) then
close(unit=1, status='delete', iostat=errorLevel) ! 如果用户选择删除输入文件, 关闭并删除输入文件
if ( errorLevel /= 0 ) stop "Error closing input file!" ! 如果关闭输入文件出错, 提示错误信息并终止程序
write(*, '(A)') 'Delete input file successed!' ! 顺利关闭并删除输入文件, 提示成功信息
exit ! 结束检测用户输入, 进入下一环节
else
close(unit=1, status='keep', iostat=errorLevel) ! 如果用户选择不删除, 则关闭输入文件
if ( errorLevel /= 0 ) stop "Error closing input file!" ! 如果关闭输入文件出错, 提示错误信息并终止程序
exit ! 顺利关闭输入文件, 结束检测用户输入, 进入下一环节
end if
end do
close(unit=2, iostat=errorLevel) ! 关闭输出文件
if ( errorLevel /= 0 ) stop "Error closing output file!" ! 如果关闭输出文件出错, 提示错误信息并终止程序
end if
write(*, '(A)') 'Program end! If the text appears garbled, please try to open the file in UTF-8 format!' ! 提示程序运行完成
contains
function Ucase(str)
character(len=*), intent(in) :: str ! 定义输入字符串
character(len=len(str)) :: ucase ! 定义函数类型
integer :: i ! 循环参数
do i = 1, len(str) ! 对输入每个字符循环
if ( lge(str(i: i), 'a') .and. lle(str(i: i), 'z') ) then ! 如果字符在a~z中
Ucase(i: i) = achar( iachar(str(i: i)) - 32 ) ! 输出大写
else
Ucase(i: i) = str(i: i) ! 如果不在, 输出原字符
end if
end do
end function Ucase
end subroutine Exercises14_18
! 习题14-19 INQUIRE语句测试等
subroutine Exercises14_19
implicit none
call SubA
call SubB
contains
subroutine SubA
implicit none
character(len=10) :: acc, fmt, act, delim
integer :: unit=35
logical :: lexist, lnamed, lopen
inquire(file='run', exist=lexist)
if ( lexist ) then
open(unit, file='run', status='old')
inquire(unit=unit, opened=lopen, exist=lexist, named=lnamed, access=acc, form=fmt, action=act, delim=delim)
write(*, 100) lexist, lopen, lnamed, acc, fmt, act, delim
100 format(1X, "File status: Exist = ", L1, ' Opened = ', L1, ' Named = ', L1, ' Access = ', A,/&
&' Format = ', A, ' Action = ', A,/&
&' Delims = ', A)
end if
end subroutine SubA
subroutine SubB
implicit none
integer :: i1=10
open (9, file='file1', access='direct', form='formatted', status='new', recl=6)
write(9, '(I6)', rec=1) i1
end subroutine SubB
end subroutine Exercises14_19
! 习题14-20 逆置方式复制文件
subroutine Exercises14_20
implicit none
character(len=128) :: inputFile, outputFile ! 输入输出文件名
integer :: errorLevel ! 错误状态码
character(len=200) :: temp ! 保存输入的临时变量
character :: overwriteSwitch ! 判断是否覆盖已存在的输出文件的变量
logical :: outputFileOpen ! 判断输出文件是否打开的变量
integer :: fileLength = 0 ! 文件长度计数
integer :: i ! 循环参数
do ! 获取输入文件名
write(*, fmt='(A)', advance='no') 'Please enter the name of the input file : ' ! 提示输入输入文件名
read(*, *) inputFile ! 读取输入文件名
open(unit=1, status='old', iostat=errorLevel, file=inputFile) ! 打开输入文件
if ( errorLevel /= 0 ) then
write(*, *) 'Warning: The input file dont exist!' ! 如果输入文件不存在, 提示错误并重新输入
else
exit ! 如果输入文件存在, 进行下一环节
end if
end do
write(*, fmt='(A)', advance='no') 'Please enter the name of the output file : ' ! 提示输入输出文件名
read(*, *) outputFile ! 读取输出文件名
open(unit=2, status='new', iostat=errorLevel, file=outputFile) ! 以新文件形式打开输出文件
if ( errorLevel /= 0 ) then
write(*, fmt='(A)', advance='no') 'Warning: The output file has existed, overwrite it? (Y/N): ' ! 如果输出文件存在, 提示是否覆盖
do
read(*, *, iostat=errorLevel) overwriteSwitch ! 读取用户选项
if ( errorLevel /= 0 .or. ( Ucase(overwriteSwitch) /= 'Y' .and. Ucase(overwriteSwitch) /= 'N' ) ) then ! 如果输入非法
write(*, fmt='(A)', advance='no') 'Illgle input, please enter again (Y/N): ' ! 提示错误, 并再次读取用户输入
elseif ( Ucase(overwriteSwitch) == 'Y' ) then
open(unit=2, status='replace', iostat=errorLevel, file=outputFile) ! 如果选择覆盖
if ( errorLevel /= 0 ) stop "Warning: Replace the output file fatal!" ! 如果打开输出文件失败, 退出程序
exit ! 如果打开输出文件成功, 进行下一环节
else
exit ! 如果选择不覆盖, 进入下一环节
end if
end do
end if
if ( Ucase(overwriteSwitch) /= 'N' ) then ! 如果输出文件不存在或用户选择覆盖
inquire(unit=2, opened=outputFileOpen, iostat=errorLevel) ! 确认输出文件已打开
if ( errorLevel /= 0 ) stop "Query output file status error " ! 如果查询输出文件状态出错, 提示错误信息并终止程序
if ( outputFileOpen .eqv. .FALSE. ) stop "The output file is not open!" ! 如果输出文件未打开, 提示错误信息并终止程序
do ! 逐行复制文件内容
read(1, '(A)', iostat=errorLevel) temp ! 读取每行给临时变量
if ( errorLevel < 0 ) then
exit ! 如果到达文件末尾, 结束读取, 进入下一环节
elseif ( errorLevel > 0 ) then
stop "01: Error reading file record!" ! 如果读取文件记录出错, 提示错误信息并终止程序
end if
fileLength = fileLength + 1 ! 记录文件行数
end do
backspace(unit=1, iostat=errorLevel) ! 回退到上一行(文件结束位置)
if ( errorLevel /= 0 ) stop "02: Error reading file record!"
backspace(unit=1, iostat=errorLevel) ! 回退到上一行(文件末端记录开始)
if ( errorLevel /= 0 ) stop "02: Error reading file record!"
do i = 1, fileLength ! 逐行复制文件内容
read(1, '(A)', iostat=errorLevel) temp ! 读取每行给临时变量
if ( errorLevel /= 0 ) then
stop "03: Error reading file record!" ! 如果读取文件记录出错, 提示错误信息并终止程序
else
write(2, '(A)', iostat=errorLevel) trim(temp) ! 将读取到的内容去除尾部空格后, 输出到输出文件
! write(*, '(A)', iostat=errorLevel) trim(temp)
if ( errorLevel /= 0 ) stop "04: Error copying records!" ! 拷贝记录出错, 提示错误信息并终止程序
end if
backspace(unit=1, iostat=errorLevel) ! 回退到本次读取记录开始
if ( errorLevel /= 0 ) stop "05: Error reading file record!"
backspace(unit=1, iostat=errorLevel) ! 回退到下次读取记录开始
if ( errorLevel /= 0 ) stop "06: Error reading file record!"
end do
write(*, fmt='(A)', advance='no') 'The copy is complete, whether to delete the input file? (Y/N): ' ! 复制文件完成, 提示用户是否删除输入文件
do ! 检测用户输出
read(*, *, iostat=errorLevel) overwriteSwitch ! 读取用户输出(这里重复使用变量了,,,)
if ( errorLevel /= 0 .or. ( Ucase(overwriteSwitch) /= 'Y' .and. Ucase(overwriteSwitch) /= 'N' ) ) then
write(*, fmt='(A)', advance='no') 'Illgle input, please enter again (Y/N): ' ! 如果输入非法, 提示错误信息并重新读取用户输入
elseif ( Ucase(overwriteSwitch) == 'Y' ) then
close(unit=1, status='delete', iostat=errorLevel) ! 如果用户选择删除输入文件, 关闭并删除输入文件
if ( errorLevel /= 0 ) stop "Error closing input file!" ! 如果关闭输入文件出错, 提示错误信息并终止程序
write(*, '(A)') 'Delete input file successed!' ! 顺利关闭并删除输入文件, 提示成功信息
exit ! 结束检测用户输入, 进入下一环节
else
close(unit=1, status='keep', iostat=errorLevel) ! 如果用户选择不删除, 则关闭输入文件
if ( errorLevel /= 0 ) stop "Error closing input file!" ! 如果关闭输入文件出错, 提示错误信息并终止程序
exit ! 顺利关闭输入文件, 结束检测用户输入, 进入下一环节
end if
end do
close(unit=2, iostat=errorLevel) ! 关闭输出文件
if ( errorLevel /= 0 ) stop "Error closing output file!" ! 如果关闭输出文件出错, 提示错误信息并终止程序
end if
write(*, '(A)') 'Program end! If the text appears garbled, please try to open the file in UTF-8 format!' ! 提示程序运行完成
contains
function Ucase(str)
character(len=*), intent(in) :: str ! 定义输入字符串
character(len=len(str)) :: ucase ! 定义函数类型
integer :: i ! 循环参数
do i = 1, len(str) ! 对输入每个字符循环
if ( lge(str(i: i), 'a') .and. lle(str(i: i), 'z') ) then ! 如果字符在a~z中
Ucase(i: i) = achar( iachar(str(i: i)) - 32 ) ! 输出大写
else
Ucase(i: i) = str(i: i) ! 如果不在, 输出原字符
end if
end do
end function Ucase
end subroutine Exercises14_20
! 习题14-21 比较格式化和未格式化文件
subroutine Exercises14_21
implicit none
integer, parameter :: sgl=selected_real_kind(p=1) ! 单精度类型数
real(sgl), dimension(10000) :: array ! 输入数组
real(sgl) :: timeFor, timeUnfor ! 输出格式化文件和非格式化文件所需时间
integer :: i ! 循环参数
integer :: errorLevel ! 错误状态码
integer, dimension(8) :: timeNow ! 计算时间用
integer, dimension(8) :: timeOld ! 计算时间用
do i = 1, 10000
call random_number(array(i)) ! 获取一个长度10000的随机数组
end do
array = array*2E6 - 1E6 ! 重设数组值的大小范围
open(unit=1, file='TempFormatted', status='replace', form='formatted', iostat=errorLevel) ! 打开格式化文件
if ( errorLevel /= 0 ) stop ""
open(unit=2, file='TempUnformatted', status='replace', form='unformatted', iostat=errorLevel) ! 打开非格式化文件
if ( errorLevel /= 0 ) stop ""
call set_timer ! 开始计算时间
write(1, '(100ES13.6)') array ! 将数组内容输出到格式化文件
call elapsed_time(timeFor) ! 计算经过时间
call set_timer ! 开始计算时间
do i = 1, 100
write(2) array(100*(i-1)+1: 100*i) ! 将数组输出到非格式化文件中
end do
call elapsed_time(timeUnfor) ! 计算经过时间
write(*, *) '写入格式化文件花费时间 ', timeFor, ' s, 写入非格式化文件花费时间 ', timeUnfor, ' s'! 输出结果
contains
subroutine set_timer ! 创建子程序1
call DATE_AND_TIME(values=timeNow) ! 调用当前时间子程序
end subroutine set_timer ! 结束子程序1
subroutine elapsed_time(timePast) ! 创建子程序2
real, intent(out) :: timePast ! 定义输出变量
timeOld = timeNow ! 传递值
call set_timer ! 调用子程序1
timePast = ((real(timeNow(3)-timeOld(3))*24 + real(timeNow(5)-timeOld(5)))&
&*60 + real(timeNow(6)-timeOld(6)))*60 + real(timeNow(7)-timeOld(7)) + &
&real(timeNow(8)-timeOld(8))/1000 ! 计算经历时间(秒)
end subroutine elapsed_time ! 结束子程序2
end subroutine Exercises14_21
! 习题14-22 比较顺序和直接访问文件
subroutine Exercises14_22
implicit none
integer, parameter :: sgl=selected_real_kind(p=1) ! 单精度类型数
real(sgl), dimension(10000) :: array ! 输入数组
real(sgl) :: timeSeqFor, timeDirFor, timeDirUnf ! 输出格式化文件和非格式化文件所需时间
real(sgl) :: temp ! 临时变量
integer :: i, j ! 循环参数
integer :: errorLevel ! 错误状态码
integer, dimension(8) :: timeNow ! 计算时间用
integer, dimension(8) :: timeOld ! 计算时间用
do i = 1, 10000
call random_number(array(i)) ! 获取一个长度10000的随机数组
end do
array = array*2E6 - 1E6 ! 重设数组值的大小范围
open(unit=1, file='TempSeqFor', status='replace', form='formatted', access='sequential', iostat=errorLevel) ! 打开格式化顺序访问文件
if ( errorLevel /= 0 ) stop ""
write(1, '(ES14.7)') array ! 将数组内容输出到格式化顺序访问文件
open(unit=2, file='TempDirFor', status='replace', form='formatted', access='direct', recl=14, iostat=errorLevel) ! 打开格式化随机访问文件
if ( errorLevel /= 0 ) stop ""
do i = 1, 10000
write(2, rec=i, fmt='(ES14.7)') array(i) ! 将数组内容输出到格式化随机访问文件
end do
inquire(iolength=i) array(1)
open(unit=3, file='TempDirUnf', status='replace', form='unformatted', access='direct', recl=i, iostat=errorLevel) ! 打开非格式化随机访问文件
if ( errorLevel /= 0 ) stop ""
do i = 1, 10000
write(3, rec=i) array(i) ! 将数组输出到非格式化随机访问文件中
end do
call set_timer ! 开始计算时间
do i = 1, 1000
rewind(unit=1, iostat=errorLevel)
if (errorLevel /= 0 ) stop ""
do j = 1, i
read(1, *) temp
end do
rewind(unit=1, iostat=errorLevel)
if (errorLevel /= 0 ) stop ""
do j = 1, 10000-i+1
read(1, *) temp
end do
end do
call elapsed_time(timeSeqFor) ! 计算经过时间
call set_timer ! 开始计算时间
do i = 1, 1000
read(2, '(ES14.7)', rec=i) temp
read(2, '(ES14.7)', rec=10000-i+1) temp
end do
call elapsed_time(timeDirFor) ! 计算经过时间
call set_timer ! 开始计算时间
do i = 1, 1000
read(3, rec=i) temp
read(3, rec=10000-i+1) temp
end do
call elapsed_time(timeDirUnf) ! 计算经过时间
write(*, *) '格式化顺序访问文件读取耗时 : ', timeSeqFor, ' s'
write(*, *) '格式化随机访问文件读取耗时 : ', timeDirFor, ' s'
write(*, *) '非格式化随机访问文件读取耗时 : ', timeDirUnf, ' s'
contains
subroutine set_timer ! 创建子程序1
call DATE_AND_TIME(values=timeNow) ! 调用当前时间子程序
end subroutine set_timer ! 结束子程序1
subroutine elapsed_time(timePast) ! 创建子程序2
real, intent(out) :: timePast ! 定义输出变量
timeOld = timeNow ! 传递值
call set_timer ! 调用子程序1
timePast = ((real(timeNow(3)-timeOld(3))*24 + real(timeNow(5)-timeOld(5)))&
&*60 + real(timeNow(6)-timeOld(6)))*60 + real(timeNow(7)-timeOld(7)) + &
&real(timeNow(8)-timeOld(8))/1000 ! 计算经历时间(秒)
end subroutine elapsed_time ! 结束子程序2
end subroutine Exercises14_22

1016
第15章习题.f90 Normal file

File diff suppressed because it is too large Load Diff

729
第16章习题.f90 Normal file
View File

@ -0,0 +1,729 @@
! ==============================================================================
! 通过 gfortran ./test.f90 -o ./run && ./run 运行
! 程序名:
! 第16章习题
! 目的:
!
! 修订记录:
! 日期 编程者 改动描述
! =================== ============= =====================================
! 2021-06-07 21:12:49 Sola 习题16-1 跳过
! 2021-06-07 21:13:08 Sola 习题16-2 改进本章创建的date类
! 2021-06-08 00:33:44 Sola 习题16-3 薪资计算
! 2021-06-08 15:27:53 Sola 习题16-4 通用多边形
! 2021-06-08 23:01:22 Sola 习题16-5 多维矢量运算
! 程序结构:
!
! ==============================================================================
! 主程序:
program Chapter16
implicit none
! call Exercises16_2
! call Exercises16_3
! call Exercises16_4
call Exercises16_5
end program Chapter16
! 习题16-2 改进本章创建的date类
module ModDateClass
implicit none
private ! 隐藏变量
type, public :: date ! 定义日期类
private
integer :: year = 1900 ! 年份, 默认1900
integer :: month = 1 ! 月份, 默认1月
integer :: day = 1 ! 日期, 默认1日
contains
procedure, public :: set_date => set_date_sub ! 设置年月日
procedure, public :: get_day => get_day_fn ! 获得日期
procedure, public :: get_month => get_month_fn ! 获得月份
procedure, public :: get_year => get_year_fn ! 获得年份
procedure, public :: is_leap_year => is_leap_year_fn ! 是否是闰年
procedure, public :: is_equal => is_equal_fn ! 年份是否相等
procedure, public :: is_earlier_than => is_earlier_fn ! 输入日期对象是否早于当前日期
procedure, public :: is_later_than => is_later_fn ! 输入日期对象是否晚于当前日期
procedure, public :: to_string => to_string_fn ! 输出当前日期的字符串形式
procedure, public :: day_of_year => day_of_year_fn ! 判断该日期是对应年份的第几天
procedure, public :: days_between => days_between_fn ! 计算两个日期之间的间隔天数
end type date
contains
subroutine set_date_sub(this, day, month, year) ! 设置日期
implicit none
class(date) :: this ! 返回自身
integer, intent(in) :: day ! 日期
integer, intent(in) :: month ! 月份
integer, intent(in) :: year ! 年份
this%day = day ! 给日期赋值, 下同
this%month = month
this%year = year
end subroutine set_date_sub
! 获得日期
integer function get_day_fn(this)
implicit none
class(date) :: this
get_day_fn = this%day
end function get_day_fn
! 获得月份
integer function get_month_fn(this)
implicit none
class(date) :: this
get_month_fn = this%month
end function get_month_fn
! 获得年份
integer function get_year_fn(this)
implicit none
class(date) :: this
get_year_fn = this%year
end function get_year_fn
! 判断是否是闰年
logical function is_leap_year_fn(this)
implicit none
class(date) :: this ! 输入自身
if ( mod(this%year, 400) == 0 ) then
is_leap_year_fn = .TRUE. ! 如果可以被400整除, 则是闰年
else if ( mod(this%year, 100) == 0 ) then
is_leap_year_fn = .FALSE. ! 如果不可以被400整除, 但可以被100整除, 则不是闰年
else if ( mod(this%year, 4) == 0 ) then
is_leap_year_fn = .TRUE. ! 如果不可以被100整除, 但是可以被4整除, 则是闰年
else
is_leap_year_fn = .FALSE. ! 如果不可以被4整除, 则不是闰年
end if
end function is_leap_year_fn
! 判断两个日期是否相同
logical function is_equal_fn(this, that)
implicit none
class(date) :: this
class(date) :: that
if ( (this%year == that%year) .and. (this%month == that%month) .and. (this%day == that%day) ) then
is_equal_fn = .TRUE.
else
is_equal_fn = .FALSE.
end if
end function is_equal_fn
! 判断输入日期是否较早
logical function is_earlier_fn(this, that)
implicit none
class(date) :: this
class(date) :: that
if ( that%year > this%year ) then
is_earlier_fn = .FALSE. ! 如果输入日期年份更大, 则输入日期更晚
else if ( that%year < this%year ) then
is_earlier_fn = .TRUE. ! 如果输入日期年份更小, 则输入日期更早
else
if ( that%month > this%month ) then
is_earlier_fn = .FALSE. ! 如果年份相同, 而输入日期月份更大, 则输入日期更晚
else if ( that%month < this%month ) then
is_earlier_fn = .TRUE. ! 如果年份相同, 而输入日期月份更小, 则输入日期更早
else
if ( that%day >= this%day ) then
is_earlier_fn = .FALSE. ! 如果年月相同, 而输入日期更大, 则其更晚
else
is_earlier_fn = .TRUE. ! 如果年月相同, 而输入日期更小, 则其更早
end if
end if
end if
end function is_earlier_fn
! 判断输入日期是否较晚, 逻辑同上相反, 注释略
logical function is_later_fn(this, that)
implicit none
class(date) :: this
class(date) :: that
if ( that%year > this%year ) then
is_later_fn = .TRUE.
else if ( that%year < this%year ) then
is_later_fn = .FALSE.
else
if ( that%month > this%month ) then
is_later_fn = .TRUE.
else if ( that%month < this%month ) then
is_later_fn = .FALSE.
else
if ( that%day >= this%day ) then
is_later_fn = .TRUE.
else
is_later_fn = .FALSE.
end if
end if
end if
end function is_later_fn
! 输入当前日期的字符串
character(len=10) function to_string_fn(this)
implicit none
class(date) :: this
character(len=2) :: dd
character(len=2) :: mm
character(len=4) :: yy
integer :: i
write(dd, '(I2.2)') this%day ! 读入日期
write(mm, '(I2.2)') this%month ! 读入月份
write(yy, '(I4.4)') this%year ! 读入年份
to_string_fn = mm//'/'//dd//'/'//yy ! 输出字符串
! do i = 1, len(to_string_fn)
! if ( iachar(to_string_fn(i: i)) == 32 ) then
! to_string_fn(i: i) = '0' ! 如果有空格, 则替换为0
! end if
! end do
end function to_string_fn
! 计算日期是当前年份的第几天
integer function day_of_year_fn(this)
implicit none
class(date) :: this
integer, dimension(12) :: daysOfMonth ! 用来保存十二个月份的天数
if ( this%month > 1 ) then ! 如果输入日期不是1月份的
daysOfMonth((/1,3,5,7,8,10,12/)) = 31 ! 大月
daysOfMonth((/4,6,9,11/)) = 30 ! 小月
if ( this%is_leap_year() ) then ! 判断是否闰年
daysOfMonth(2) = 29 ! 闰年二月
else
daysOfMonth(2) = 28 ! 非闰年二月
end if
day_of_year_fn = sum(daysOfMonth(1: this%month)) + this%day ! 计算天数
else
day_of_year_fn = this%day ! 如果是1月, 直接计算天数
end if
end function day_of_year_fn
! 计算两个日期之间相隔天数
integer function days_between_fn(this, that)
class(date) :: this
class(date) :: that
integer :: year_days ! 对应年份天数
integer :: step ! 步长
integer :: i ! 循环参数
if ( this%is_earlier_than(that) ) then ! 如果输入年份更早
step = -1 ! 步长为-1
else
step = 1 ! 否则, 步长为1
end if
days_between_fn = 0 ! 初始化间隔
if ( this%year /= that%year ) then ! 如果非同年
do i = this%year, that%year, step ! 对两个年份之间的每一年份循环
if ( i == that%year ) exit ! 如果到达最后一个循环, 则退出(不计算最后一个年份的天数)
if ( mod(i, 400) == 0 ) then ! 判断是否是闰年, 并赋值
year_days = 366
else if ( mod(i, 100) == 0 ) then
year_days = 365
else if ( mod(i, 4) == 0 ) then
year_days = 366
else
year_days = 365
end if
days_between_fn = days_between_fn + year_days*step ! 间隔天数增加当前年份天数*步长
end do
end if
days_between_fn = days_between_fn + that%day_of_year() - this%day_of_year() ! 计算总天数
end function days_between_fn
end module ModDateClass
subroutine Exercises16_2
use ModDateClass
implicit none
type(date) :: date1
type(date) :: date2
type(date) :: date3
integer :: yy, mm, dd
integer :: errorLevel
do
write(*, '(A)', advance='no') 'Please enter the date1 like YYYY MM DD: '
read(*, *, iostat=errorLevel) yy, mm, dd
if ( errorLevel /= 0 ) then
write(*, *) 'Wrong input, please try again.'
else
exit
end if
end do
call date1%set_date(dd, mm, yy)
do
write(*, '(A)', advance='no') 'Please enter the date2 like YYYY MM DD: '
read(*, *, iostat=errorLevel) yy, mm, dd
if ( errorLevel /= 0 ) then
write(*, *) 'Wrong input, please try again.'
else
exit
end if
end do
call date2%set_date(dd, mm, yy)
call date3%set_date(1, 1, 1900)
write(*, 1) date1%to_string(), date1%day_of_year()
1 format('---- ', A, ' is the ', I3, ' days in this year.')
write(*, 2) date1%to_string(), date3%days_between(date1)
2 format('From 01/01/1900 to ', A, ' has ', I6, ' days.')
write(*, 3) date1%to_string(), date2%to_string(), date1%days_between(date2)
3 format('From ', A, ' to ', A, ' has ', I6, ' days.')
end subroutine Exercises16_2
! empolyee_class
module ModEmployeeClass
implicit none
! private
type, public :: employee
character(len=30) :: firstName ! 名
character(len=30) :: lastName ! 姓
character(len=11) :: ssn ! 工作号
real :: pay = 0 ! 薪资
contains
procedure, public :: SetEmployee => SetEmployeeSub ! 设置信息
procedure, public :: SetName => SetNameSub ! 设置名称
procedure, public :: SetSsn => SetSsnSub ! 设置工作号
procedure, public :: GetFirstName => GetFirstNameFn ! 获得名
procedure, public :: GetLastName => GetLastNameFn ! 获得姓
procedure, public :: GetSsn => GetSsnFn ! 获得工作号
! procedure(CalcPay), public, deferred :: CalcPay ! 好像用不了抽象类
procedure, public :: CalcPay => CalcPayFn ! 计算薪资
end type employee
! abstract interface
! real function CalcPay(this, hours)
! implicit none
! class(employee) :: this
! real, intent(in) :: hours
! end function CalcPay
! end interface
private :: SetEmployeeSub, SetNameSub, SetSsnSub
private :: GetFirstNameFn, GetLastNameFn, GetSsnFn, CalcPayFn
contains
subroutine SetEmployeeSub(this, first, last, ssn)
implicit none
class(employee) :: this
character(len=*) :: first
character(len=*) :: last
character(len=*) :: ssn
this%firstName = first
this%lastName = last
this%ssn = ssn
this%pay = 0
end subroutine SetEmployeeSub
subroutine SetNameSub(this, first, last)
implicit none
class(employee) :: this
character(len=*), intent(in) :: first
character(len=*), intent(in) :: last
this%firstName = first
this%lastName = last
end subroutine SetNameSub
subroutine SetSsnSub(this, ssn)
implicit none
class(employee) :: this
character(len=*), intent(in) :: ssn
this%ssn = ssn
end subroutine SetSsnSub
character(len=30) function GetFirstNameFn(this)
implicit none
class(employee) :: this
GetFirstNameFn = this%firstName
end function GetFirstNameFn
character(len=30) function GetLastNameFn(this)
implicit none
class(employee) :: this
GetLastNameFn = this%lastName
end function GetLastNameFn
character(len=11) function GetSsnFn(this)
implicit none
class(employee) :: this
GetSsnFn = this%ssn
end function GetSsnFn
real function CalcPayFn(this, hours) ! 空函数, 用来重载用
implicit none
class(employee) :: this
real, intent(in) :: hours
end function CalcPayFn
end module ModEmployeeClass
! salaried_employee_class
module ModSalariedEmployeeClass
use ModEmployeeClass
implicit none
type, public, extends(employee) :: salariedEmployee ! 扩展类, 有固定底薪
private
real :: salary = 0 ! 底薪
contains
procedure, public :: SetSalary => SetSalarySub
procedure, public :: CalcPay => CalcPayFn
end type salariedEmployee
private :: CalcPayFn, SetSalarySub
contains
subroutine SetSalarySub(this, salary)
implicit none
class(salariedEmployee) :: this
real, intent(in) :: salary
this%pay = salary
this%salary = salary
end subroutine SetSalarySub
real function CalcPayFn(this, hours)
implicit none
class(salariedEmployee) :: this
real, intent(in) :: hours
CalcPayFn = this%salary ! 工资 = 底薪
end function CalcPayFn
end module ModSalariedEmployeeClass
! hourly_employee_class
module ModHourlyEmployeeClass
use ModEmployeeClass
implicit none
type, public, extends(employee) :: hourlyEmployee ! 扩展类, 小时工
private
real :: rate = 0 ! 每小时薪资
contains
procedure, public :: SetPayRate => SetPayRateSub
procedure, public :: CalcPay => CalcPayFn
end type hourlyEmployee
private :: CalcPayFn, SetPayRateSub
contains
subroutine SetPayRateSub(this, rate)
implicit none
class(hourlyEmployee) :: this
real, intent(in) :: rate
this%rate = rate
end subroutine SetPayRateSub
real function CalcPayFn(this, hours)
implicit none
class(hourlyEmployee) :: this
real, intent(in) :: hours
this%pay = hours*this%rate
CalcPayFn = this%pay
end function CalcPayFn
end module ModHourlyEmployeeClass
! salary_plus_employee
module ModSalaryPlusEmployeeClass
use ModEmployeeClass
implicit none
type, public, extends(employee) :: salaryPlusEmployee ! 扩展类, 有底薪, 有加班费
private
real :: salary = 0 ! 底薪
real :: rate = 0 ! 加班小时薪资
contains
procedure, public :: SetSalary => SetSalarySub
procedure, public :: SetPayRate => SetPayRateSub
procedure, public :: CalcPay => CalcPayFn
end type salaryPlusEmployee
private :: SetPayRateSub, SetSalarySub, CalcPayFn
contains
subroutine SetSalarySub(this, salary)
implicit none
class(salaryPlusEmployee) :: this
real, intent(in) :: salary
this%salary = salary
end subroutine SetSalarySub
subroutine SetPayRateSub(this, rate)
implicit none
class(salaryPlusEmployee) :: this
real, intent(in) :: rate
this%rate = rate
end subroutine SetPayRateSub
real function CalcPayFn(this, hours)
implicit none
class(salaryPlusEmployee) :: this
real, intent(in) :: hours
if ( hours > 42 ) then
CalcPayFn = this%salary + this%rate*(hours - 42.)
else
CalcPayFn = this%salary
end if
end function CalcPayFn
end module ModSalaryPlusEmployeeClass
! 习题16-3 薪资计算
subroutine Exercises16_3
use ModEmployeeClass
use ModHourlyEmployeeClass
use ModSalariedEmployeeClass
use ModSalaryPlusEmployeeClass
class(employee), pointer :: workerPtr => null()
type(salariedEmployee), pointer :: workerPtr1 => null()
type(hourlyEmployee), pointer :: workerPtr2 => null()
type(salaryPlusEmployee), pointer :: workerPtr3 => null()
integer :: i
integer :: errorLevel
character(len=30) :: firstName
character(len=30) :: lastName
character(len=11) :: ssn
real :: temp
real :: pay
real :: hours
write(*, '(A)', advance='no') 'Please input your first name : '
read(*, *) firstName
write(*, '(A)', advance='no') 'Please input your last name : '
read(*, *) lastName
write(*, '(A)', advance='no') 'Please input your ssn : '
read(*, *) ssn
write(*, 1, advance='no')
1 format(&
&'There are three types of the work below.',/&
&' 1) Salaried Employee',/&
&' 2) Hourly Employee',/&
&' 3) Salary Plus Employee',/&
&'Please choose your work type : ')
do
read(*, *, iostat=errorLevel) i
if ( (errorLevel /= 0) .or. (i > 3) .or. (i < 1) ) then
write(*, '(A)', advance='no') 'Warning: Illegal input, please try again: '
else
exit
end if
end do
select case(i)
case(1)
if ( associated(workerPtr1) ) deallocate(workerPtr1, stat=errorLevel)
if ( errorLevel /= 0 ) stop ""
allocate(workerPtr1, stat=errorLevel)
if ( errorLevel /= 0 ) stop ""
do
write(*, '(A)', advance='no') 'Please input the salary : '
read(*, *, iostat=errorLevel) temp
if ( errorLevel /= 0 ) then
write(*, *) ''
else
call workerPtr1%SetSalary(temp)
exit
end if
end do
workerPtr => workerPtr1
deallocate(workerPtr1, stat=errorLevel)
if ( errorLevel /= 0 ) stop ""
case(2)
if ( associated(workerPtr2) ) deallocate(workerPtr2, stat=errorLevel)
if ( errorLevel /= 0 ) stop ""
allocate(workerPtr2, stat=errorLevel)
if ( errorLevel /= 0 ) stop ""
do
write(*, '(A)', advance='no') 'Please input the rate : '
read(*, *, iostat=errorLevel) temp
if ( errorLevel /= 0 ) then
write(*, *) ''
else
call workerPtr2%SetPayRate(temp)
exit
end if
end do
workerPtr => workerPtr2
deallocate(workerPtr2, stat=errorLevel)
if ( errorLevel /= 0 ) stop ""
case(3)
if ( associated(workerPtr3) ) deallocate(workerPtr3, stat=errorLevel)
if ( errorLevel /= 0 ) stop ""
allocate(workerPtr3, stat=errorLevel)
if ( errorLevel /= 0 ) stop ""
do
write(*, '(A)', advance='no') 'Please input the salary : '
read(*, *, iostat=errorLevel) temp
if ( errorLevel /= 0 ) then
write(*, *) ''
else
call workerPtr3%SetSalary(temp)
exit
end if
end do
do
write(*, '(A)', advance='no') 'Please input the rate : '
read(*, *, iostat=errorLevel) temp
if ( errorLevel /= 0 ) then
write(*, *) ''
else
call workerPtr3%SetPayRate(temp)
exit
end if
end do
workerPtr => workerPtr3
deallocate(workerPtr3, stat=errorLevel)
if ( errorLevel /= 0 ) stop ""
end select
write(*, '(A)', advance='no') 'Please input the work time a month (h) : '
read(*, *) hours
call workerPtr%SetEmployee(firstName, lastName, ssn)
write(*, 2) workerPtr%GetFirstName(), workerPtr%GetLastName(), workerPtr%GetSsn(), workerPtr%CalcPay(hours)
2 format(&
&'Please enjoy the squeeze of capitalists!',/&
&'Your pay slip:',/&
&' FIRST NAME LAST NAME SSN PAYCHECK',/&
&'============================== ============================== =========== ==========',/&
&A, 1X, A, 1X, A, 1X, '$', F9.2)
deallocate(workerPtr, stat=errorLevel)
if ( errorLevel /= 0 ) stop ""
end subroutine Exercises16_3
! 习题16-4 通用多边形
module ModPointClass
implicit none
type, public :: point
real :: x
real :: y
end type point
end module ModPointClass
module ModShapeClass
implicit none
type, public :: shape
contains
procedure, public :: Area => CalcAreaFn
procedure, public :: Perimeter => CalcPerimeterFn
procedure, public :: ToString => ToStringFn
end type shape
private :: CalcAreaFn, CalcPerimeterFn, ToStringFn
contains
real function CalcAreaFn(this)
implicit none
class(shape) :: this
CalcAreaFn = 0.
end function CalcAreaFn
real function CalcPerimeterFn(this)
implicit none
class(shape) :: this
CalcPerimeterFn = 0.
end function CalcPerimeterFn
character(len=50) function ToStringFn(this)
implicit none
class(shape) :: this
ToStringFn = ''
end function ToStringFn
end module ModShapeClass
module ModPolygonClass
use ModPointClass
implicit none
type, public :: polygon
type(point), dimension(:), allocatable :: p
contains
procedure, public :: SetShape => SetShapeSub
procedure, public :: Area => CalcAreaFn
procedure, public :: Perimeter => CalcPerimeterFn
end type polygon
contains
subroutine SetShapeSub(this, num, pointArray)
class(polygon) :: this
integer, intent(in), optional :: num
class(point), dimension(:), allocatable, intent(in), optional :: pointArray
integer :: errorLevel
integer :: i=0
integer :: n
if ( present(num) ) then
n = num
else
write(*, '(A)', advance='no') 'Please enter the number of the points : '
read(*, *) n
end if
do
if ( n < 3 ) then
write(*, '(A)', advance='no') 'The number of the points isn''t enough, try again : '
read(*, *) n
else
exit
end if
end do
if ( allocated(this%p) ) then
deallocate(this%p, stat=errorLevel)
if ( errorLevel /= 0 ) stop ""
end if
allocate(this%p(n), stat=errorLevel)
if ( errorLevel /= 0 ) stop ""
if ( present(pointArray) ) then
do
if ( size(pointArray, 1) /= n ) then
write(*, '(A)') 'Warning: Input array dimensions do not match!'
write(*, '(A)') 'Please enter the coordinates in counterclockwise order.'
do
i = i + 1
if ( i == n + 1 ) exit
write(*, '(A, I3, A)', advance='no') 'Please enter the coordinate', i, ' : '
read(*, *, iostat=errorLevel) this%p(i)%x, this%p(i)%y
if ( errorLevel /= 0 ) then
write(*, '(A)') ''
i = i - 1
end if
end do
else
this%p = pointArray
exit
end if
end do
else
write(*, '(A)') 'No coordinates entered, Please enter the coordinates in counterclockwise order like x y !'
do
i = i + 1
if ( i == n + 1 ) exit
write(*, '(A, I3, A)', advance='no') 'Please enter the coordinate', i, ' : '
read(*, *, iostat=errorLevel) this%p(i)%x, this%p(i)%y
if ( errorLevel /= 0 ) then
write(*, '(A)') 'Warning: Illegal input information, please try again!'
i = i - 1
end if
end do
end if
end subroutine SetShapeSub
real function CalcAreaFn(this)
implicit none
class(polygon) :: this
integer :: i
CalcAreaFn = 0
do i = 1, size(this%p, 1)-1
CalcAreaFn = CalcAreaFn + (this%p(i)%x*this%p(i+1)%y - this%p(i+1)%x*this%p(i)%y)/2.
end do
CalcAreaFn = CalcAreaFn + (this%p(size(this%p, 1))%x*this%p(1)%y - this%p(1)%x*this%p(size(this%p, 1))%y)/2.
end function CalcAreaFn
real function CalcPerimeterFn(this)
implicit none
class(polygon) :: this
integer :: i
do i = 1, size(this%p, 1)-1
CalcPerimeterFn = CalcPerimeterFn + sqrt((this%p(i+1)%x - this%p(i)%x)**2 + (this%p(i+1)%y - this%p(i)%y)**2)
end do
CalcPerimeterFn = CalcPerimeterFn +&
& sqrt((this%p(1)%x - this%p(size(this%p, 1))%x)**2 + (this%p(1)%y - this%p(size(this%p, 1))%y)**2)
end function CalcPerimeterFn
end module ModPolygonClass
subroutine Exercises16_4
use ModPolygonClass
use ModPointClass
implicit none
integer, parameter :: numPolygon=4
type(polygon), dimension(numPolygon) :: shape1
call shape1%SetShape()
! write(*, '(A, F6.2)') 'The area of the polygon is : ', shape1%Area()
! write(*, '(A, F6.2)') 'The perimeter of the polygon is: ', shape1%Perimeter()
write(*, 1) size(shape1%p, 1), shape1%Area(), shape1%Perimeter()
1 format(/&
&'POINTS AREA PERIMETER',/&
&'====== ========== ===========',/&
T2, I3, T9, F6.2, T21, F6.2)
end subroutine Exercises16_4
! 习题16-5 多维矢量运算
module ModVecClass
implicit none
type, abstract, public :: vec
real :: x
real :: y
contains
generic(plus1), public, deferred :: add => plus1
end type vec
private :: plus1
! interface :: operator(+)
! module procedure plus1
! end interface
! abstract interface operator(+)
! module procedure plus1
! end interface
abstract interface
function plus1(this, that)
implicit none
class(type1) :: this
class(type1) :: that
class(type1) :: plus1
end function plus1
end interface
end module ModVecClass
module ModVec2dClass
use ModVecClass
implicit none
type, extends(vec), public :: vec2d
end type vec2d
private :: VecAddFn, VecSubFn
end module ModVec2dClass
subroutine Exercises16_5
use ModVecClass
use ModVec2dClass
implicit none
type(vec2d), pointer :: vector1
type(vec2d), pointer :: vector2
class(vec), pointer :: vector
integer :: errorLevel
! allocate(vector1, stat=errorLevel)
! if ( errorLevel /= 0 ) stop ""
! vector1 = vec2d(1, 2)
! allocate(vector2, stat=errorLevel)
! if ( errorLevel /= 0 ) stop ""
! vector2 = vec2d(1, 3)
! vector => vector1
! call vector%Add(vector2)
! write(*, *) vector%x, vector%y
! write(*, *) vector%Add(vector2)
end subroutine Exercises16_5

302
第2章习题.f90 Normal file
View File

@ -0,0 +1,302 @@
! 2021:04:14 20:02:17 标准程序格式
! program name
! !
! ! 目的:
! !
! !
! ! 修订记录:
! ! 日期 编程者 改动描述
! ! =================== ============= ======================
! !
! !
! ! 程序结构:
! !
! implicit none
! ! 数据字典
! ! 声明常量
! REAL, PARAMETER :: PI=3.14159265 ! PI值
! REAL, PARAMETER :: e=2.718281828459 ! 自然对数
! INTEGER, PARAMETER :: arrayLength=20 ! 数组基准长度
! ! 声明变量
! ! 变量初始化
! ! 数据输入
! ! 运算过程
! ! 结果输出
! end program name
! 2021:04:14 17:31:01 一个用于读取文件中所有数值的程序案例
! program name
! ! =============================================================
! ! 目的:
! ! 遍历一个文件内的所有变量(需要全部是实数或整数)
! ! 修订记录:
! ! 日期 编程者 改动描述
! ! =================== ============= ======================
! ! 2021-04-14 17:46:57 Sola 编写源代码并校正格式
! ! =============================================================
! implicit none
! ! 数据字典
! ! 结构需要
! integer :: i ! 控制读取字符所在位置
! integer :: errorLevel ! 检查错误信息
! integer :: valueStart ! 读取数值开始位置
! integer :: valueEnd ! 读取数值结束位置
! real :: value ! 读取的数值内容
! character(len=128) :: allValue ! 所在行字符内容
! character(len=128) :: selectValue ! 读取所在行第i个字符内容
! character(len=128) :: readValue ! 读取的字符内容
! ! 使用者自定义
! ! 声明常量
! REAL, PARAMETER :: PI=3.14159265 ! PI值
! REAL, PARAMETER :: e=2.718281828459 ! 自然对数
! ! 声明变量
! ! 变量初始化
! valueStart=1
! ! 打开文件
! open (unit=1, file='content', status='old', action='read', iostat=errorLevel)
! if (errorLevel > 0) stop "读取文件出错"
! ! 遍历数值
! do
! read(1, '(A128)', iostat=errorLevel) allValue ! 读取行内容
! if (errorLevel < 0) exit ! 如果到达最后一行, 退出循环
! if (errorLevel > 0) stop "读取行出错" ! 读取行内容出错, 退出程序
! ! 遍历行内字符
! do i=1, len_trim(allValue), 1
! selectValue=allValue(i:i) ! 读取第i个字符
! if ( .not. ( trim(selectValue) == ',' .or. i == len_trim(allValue)) ) then
! cycle ! 如果不是逗号或到达末尾, 则跳过此次循环
! else ! 如果是逗号或到达末尾
! if ( i == len_trim(allValue) ) then
! valueEnd=i ! 如果是到达末尾, 则数值结束位置为i
! else
! valueEnd=i-1 ! 如果并未达到末尾, 则数值结束位置为i-1
! end if
! readValue=allValue(valueStart:valueEnd) ! 读取当前数值
! read(readValue, '(F5.1)', iostat=errorLevel) value ! 将当前数值赋值给一个实数
! if (errorLevel > 0) stop "存在非合法数值,请检查" ! 赋值存在错误, 退出程序
! valueStart=i+1 ! 下一次数值的开始位置为i+1
! end if
! end do
! valueStart=1 ! 开始新一行, 并将数值开始位置重置
! end do
! close (unit=1) ! 关闭文件
! end program name
! program example
! implicit none
! end program example
! 2021:04:08 19:23:29 2-9
! PROGRAM triangle
! IMPLICIT NONE
! REAL :: a, b, c, theta
! REAL, PARAMETER :: PI=3.14159265
! WRITE (*,*) 'Enter the length of the hypotenuse C:'
! READ (*,*) c
! WRITE (*,*) 'Enter the angle THETA in degrees:'
! READ (*,*) theta
! a = c * COS(theta)
! b = c * SIN(theta)
! WRITE (*,*) 'The length of the adjacent side is ', a
! WRITE (*,*) 'The length of the opppsite side is ', b
! END PROGRAM triangle
! 2021:04:08 19:44:56 2-10
! program example
! implicit none
! real :: a, b, c
! integer :: k, l, m
! read (*,*) a, b, c, k
! read (*,*) l, m
! write (*,*) a, b, c, k, l, m
! end program example
! 2021:04:09 19:44:46 2-11
! program example
! implicit none
! real :: hourWages, workTime, allWages
! write (*,*) 'How many wages per hour?'
! read (*,*) hourWages
! write (*,*) 'How much time work a week?'
! read (*,*) workTime
! allWages = hourWages * workTime
! write (*,*) 'You can get the wages of $', allWages, ' a week'
! end program example
! 2021:04:09 20:31:02 2-12
! program example
! implicit none
! real :: m, h, v, PE, KE, E
! real, PARAMETER :: g=10.0
! write (*,*) 'Please enter the m h v for coculate the energy of the item above the ground.'
! read (*,*) m, h, v
! PE=m*g*h
! KE=1./2.*m*v**2
! E=PE + KE
! write (*,*) 'The energy of the item is:', E, 'J'
! end program example
! 2021:04:09 20:37:44 2-13
! program example
! implicit none
! real, parameter :: g=10.0
! real :: v, h
! write (*,*) 'Please enter the highte of the item.'
! read (*,*) h
! v=sqrt(2.*g*h)
! write (*,*) 'The speed is', v, 'm/s'
! end program example
! 2021:04:09 20:42:37 2-14
! program example
! implicit none
! real, parameter :: c=2.9979E8
! real :: E, m, t, P
! write (*,*) 'Please enter the days of reactor run a year.'
! read (*,*) t
! write (*,*) 'Please enter the power(mW) of the reactor.'
! read (*,*) P
! E=P*t*24.*60*60
! m=E*1E6/c**2
! write (*,*) m, 'kg of consumed material per year.'
! end program example
! 2021:04:09 21:03:57 2-17
! program example
! implicit none
! real, parameter :: g=10.0, PI=3.14159265
! real :: L, T
! write (*,*) 'Please input pendulum length(m).'
! read (*,*) L
! T = 2*PI*sqrt(L/g)
! write(unit=*, fmt=*) 'The oscillation period of the pendulum is', T, 's'
! end program example
! 2021:04:09 21:12:01 2-18
! program example
! implicit none
! real :: a, b, c
! write(unit=*, fmt=*) 'Please enter the length(cm) of the two right angle sides.'
! read (*,*) a, b
! c = sqrt(a**2+b**2)
! write(unit=*, fmt=*) 'The length of the hypotenuse of the right triangle is', c, 'cm.'
! end program example
! 2021:04:09 21:18:48 2-19
! program example
! implicit none
! real :: b, x, calculationResult, calculationCheck
! write(unit=*, fmt=*) 'Please enter logarithm x and base b respectively'
! read (*,*) x, b
! calculationResult = log10(x)/log10(b)
! calculationCheck = log(x)/log(b)
! write(unit=*, fmt=*) 'The calculation result is', calculationResult, 'and the check result is', calculationCheck
! end program example
! 2021:04:09 21:27:29 2-20
! program example
! implicit none
! a = 1
! end program example
! 2021:04:09 21:29:00 2-21
! program example
! implicit none
! real :: d, x1, x2, y1, y2
! write(unit=*, fmt=*) 'Please enter the coordinates of the first point.'
! read (*,*) x1, y1
! write(unit=*, fmt=*) 'Please enter the coordinates of the second point.'
! read (*,*) x2, y2
! d = sqrt((x1-x2)**2+(y1-y2)**2)
! write(unit=*, fmt=*) 'The distance between the two points is', d
! end program example
! 2021:04:09 21:33:10 2-22
! program example
! implicit none
! real :: dB, P2
! real, parameter :: P1=1
! write(unit=*, fmt=*) '请输入接受输入能源的级别'
! read (*,*) P2
! dB = 10*log10(P2/P1)
! write(unit=*, fmt=*) '该输入的分贝值为:', dB, 'dB'
! end program example
! 2021:04:09 21:37:13 2-23
! program example
! implicit none
! real :: x, calculationResult, calculationCheck
! real, parameter :: e=2.718281828459
! write(unit=*, fmt=*) '请输入需要计算的双曲余弦值的x值'
! read (*,*) x
! calculationResult = (e**x+e**(-x))/2.
! calculationCheck = COSH(x)
! write(unit=*, fmt=*) '计算结果为:', calculationResult, '核对结果为:', calculationCheck
! end program example
! 2021:04:09 21:42:29 2-24
! program example
! implicit none
! real :: P, F, APR
! integer :: m, n
! write(unit=*, fmt=*) '请输入每年计算复利的次数以及储存年数'
! read (*,*) m, n
! P = 1000.00
! APR = 5
! F = P*(1.+APR/(100.*m))**(m*n)
! write(unit=*, fmt=*) '该账户', n, '年后存款将达到$', F
! end program example
! 2021:04:09 22:07:57 2-25
! program example
! implicit none
! real :: f0, L, C
! real, parameter :: PI=3.14159265
! write(unit=*, fmt=*) '请输入电感值(mH)与电容值(nF)'
! read (*,*) L, C
! f0 = 1/(2*PI*sqrt(L*C))
! write(unit=*, fmt=*) '该无线电的频率为:', f0, 'hz'
! end program example
! 2021:04:09 22:12:51 2-26
! program example
! implicit none
! real :: a, v, r
! real, parameter :: g=9.81, machToMeter=340
! v=0.8*machToMeter
! a=2.5*g
! r = v**2/a
! write(unit=*, fmt=*) '(a) 飞机的飞行半径为', r, 'm'
! v = 1.5*machToMeter
! r = v**2/a
! write(unit=*, fmt=*) '(b) 飞机的飞行半径为', r, 'm'
! a = 7*g
! r = v**2/a
! write(unit=*, fmt=*) '(c) 飞机的飞行最小半径为', r, 'm'
! end program example
! 2021:04:09 22:21:16 2-27
! program example
! implicit none
! real, parameter :: G=6.673E-11
! real :: vescEarth, vescMoon, vescGu, vescJuipter, M, R
! M = 6.0E24
! R = 6.4E6
! vescEarth = sqrt(2*G*M/R)
! M = 7.4E22
! R = 1.7E6
! vescMoon = sqrt(2*G*M/R)
! M = 8.7E20
! R = 4.7E5
! vescGu = sqrt(2*G*M/R)
! M = 1.9E27
! R = 7.1E7
! vescJuipter = sqrt(2*G*M/R)
! write(unit=*, fmt=*) '地球上物体的逃逸速度为', vescEarth, 'm/s'
! write(unit=*, fmt=*) '月球上物体的逃逸速度为', vescMoon, 'm/s'
! write(unit=*, fmt=*) '谷神星上物体的逃逸速度为', vescGu, 'm/s'
! write(unit=*, fmt=*) '木星上物体的逃逸速度为', vescJuipter, 'm/s'
! end program example

921
第5章习题.f90 Normal file
View File

@ -0,0 +1,921 @@
! 2021:04:12 17:39:07 5-1
! program example
! implicit none
! real :: numSquareRoot
! integer :: i, numSquare, numCube
! ! write(*, '(1X, "Table of Square Roots, Squares, and Cubes"')
! write(*, 1)
! 1 FORMAT(1X, "Table of Square Roots, Squares, and Cubes"/&
! &1X, " Number Square Root Square Cube"/&
! &1X, " ====== =========== ====== ===="/&
! &1X)
! ! write(*, '(1X, " Number Square Root Square Cube")')
! ! write(*, '(1X, " ====== =========== ====== ===="')
! DO i=1,10,1
! numSquareRoot = sqrt(real(i))
! numSquare = i**2
! numCube = i**3
! write(*, 2) i, numSquareRoot, numSquare, numCube
! 2 FORMAT(1X, T5, I2, T13, F8.6, T27, I3, T36, I4)
! END DO
! end program example
! 2021:04:13 01:41:33 5-3.1
! program example
! implicit none
! integer :: inforError
! OPEN (UNIT=25, FILE='IN052691', STATUS='OLD', ACTION='READ', IOSTAT=inforError)
! if ( inforError == 0 ) then
! write(*,'(1X, "成功打开文件")')
! else
! write(*,'(1X, "打开文件失败,错误代码为", I3)') inforError
! end if
! close (unit= 25)
! end program example
! 2021:04:13 01:57:01 5-3.2
! program example
! implicit none
! integer :: inforError
! character(len=8) :: out_name
! out_name='12345678'
! open (unit=1, STATUS='new', ACTION='readwrite', file=out_name, IOSTAT=inforError)
! if ( inforError /= 0 ) then
! write(*, '(1X, "新建文件失败")')
! else
! write(*, '(1X, "新建文件成功")')
! endif
! close (unit=1)
! end program example
! 2021:04:13 02:19:06 5-3.4
! program name
! implicit none
! character(len=20) :: first, last, varName, varValue
! integer :: i=0, errorLevel=0, length=0
! open(unit=1, file='content', status='old', action='read', iostat=errorLevel)
! if ( errorLevel > 0 ) stop "出现了错误"
! do
! read(1,*, iostat=errorLevel) varName, varValue
! if ( errorLevel < 0 ) EXIT
! length=length+1
! if ( varName == 'first' ) first=varValue
! if ( varName == 'last' ) last=varValue
! end do
! rewind (unit=1)
! read(1,'(T1, A)') varValue
! write(*,*) first, last, varValue
! close (unit=1)
! end program name
! 2021:04:13 10:13:10 5.6.3 5-3.a
! program name
! implicit none
! integer :: i
! character(len=20) :: fmt
! fmt="('1','i= ', I6.5)"
! i=-123
! write(*,fmt) i
! end program name
! 2021:04:13 10:25:00 5.6.3 5-3.c
! program name
! implicit none
! integer :: i1, i2
! i1=10
! i2=4**2
! write(*, 300) i1 > i2
! 300 format (' ','Result = ', L6)
! end program name
! 2021:04:13 16:56:13 5.6.3 5-7
! program name
! implicit none
! integer :: i=0, j=0, writeLocate
! real :: value0, value1, value2, value3, value4, value5, value6, value7, value8, value9
! write(*, '(T13, "表格1~10之间以0.1为一级各个数的以10为底的对数")')
! write(*,1)
! 1 format (T9, 'X.0', T16, 'X.1', T23, 'X.2', T30, 'X.3', T37, 'X.4', T44, 'X.5', T51, 'X.6',&
! & T58, 'X.7', T65, 'X.8', T72, 'X.9')
! do i = 1, 10, 1
! value0=log10(real(i)+0)
! value1=log10(real(i)+0.1)
! value2=log10(real(i)+0.2)
! value3=log10(real(i)+0.3)
! value4=log10(real(i)+0.4)
! value5=log10(real(i)+0.5)
! value6=log10(real(i)+0.6)
! value7=log10(real(i)+0.7)
! value8=log10(real(i)+0.8)
! value9=log10(real(i)+0.9)
! write(*,2) real(i), value0, value1, value2, value3, value4, value5, value6, value7, value8, value9
! 2 format (T2, F4.1, T8, F5.3, T15, F5.3, T22, F5.3, T29, F5.3, T36, F5.3, T43, F5.3, T50, F5.3,&
! & T57, F5.3, T64, F5.3, T71, F5.3)
! end do
! end program name
! 2021:04:13 17:40:36 5.6.3 5-8
! program name
!
! implicit none
! integer :: i=0, errorLevel, j=0
! real :: average=0, sum=0, standardDeviation=0, value=0
! open (unit=1, file='content', status='old', action='read', iostat=errorLevel)
! if ( errorLevel /= 0 ) stop "Open file fatal!"
! do
! read(1,*,iostat=errorLevel) value
! if ( errorLevel < 0 ) exit
! sum=sum+value
! i=i+1
! end do
! average=sum/i
! rewind (unit=1)
! do j=1,i,1
! read(1,*,iostat=errorLevel) value
! if ( errorLevel /= 0 ) exit
! standardDeviation=(value-average)**2+standardDeviation
! end do
! standardDeviation=sqrt(standardDeviation/i)
! write(*,2) i, sum, average, standardDeviation
! 2 format (1X, '共统计', I3, '个数值,样本总和为', F8.1, ',平均值为', F8.1, ',标准偏差为', F8.1)
! close (unit=1)
!
! end program name
! 2021:04:13 20:11:58 5.6.3 5-13
! program name
!
! implicit none
! integer :: timeSecond, errorLevel, HH, MM, SS
! write(*,'(1X, "Please enter the start time in second(0~86400)")')
! do
! read(*,*, iostat=errorLevel) timeSecond
! if ( errorLevel /= 0 ) then
! write(*,'(1X, "输入数值格式不正确请输入在0~86400之间的整数")')
! else
! if ( timeSecond > 86400 .or. timeSecond < 0 ) then
! write(*,'(1X, "请在正确的范围内输入数值(0~86400)")')
! else
! exit
! end if
! end if
! end do
! SS=timeSecond-timeSecond/60*60
! MM=(timeSecond-timeSecond/(60*60)*3600)/60
! HH=timeSecond/(60*60)
! write(*,1) HH, MM, SS
! 1 format (1X, "当前的时间为:", I2.2, ":", I2.2, ":", I2.2, ' (24h)')
!
! end program name
! 2021:04:13 20:31:14 5.6.3 5-14
! program name
! implicit none
! integer :: h
! real :: G, M, R, gg=0
! G=6.672E-11
! M=5.98E24
! R=6371E3
! write(*,'(1X, "表格:高度相对于重力加速度一览表"/&
! &1X, "高度(km)", T17, "重力加速度(米/秒2"/&
! &1x, "=========", T15, "==================")')
! do h=0,40000,500
! gg=-G*M/(R+real(h)*1000)**2
! write(*,1) h, gg
! 1 format (T3, I5, T18, F8.2)
! end do
! end program name
! 2021-04-13 21:48:55 5.6.3 5-21
! program name
! implicit none
! integer :: unit=8, errorLevel
! open (UNIT=unit, status="scratch", iostat=errorLevel)
! write(*,*) errorLevel
! end program name
! 2021-04-13 21:58:06 5.6.3 5-26
! program name
! implicit none
! integer :: i, errorLevel
! real :: max, min, value
! character(len=20) :: maxRow, minRow, str
! open (unit=1, file='content', status='old', action='read', iostat=errorLevel)
! if ( errorLevel /= 0 ) stop "Open file fatal!"
! i=0
! do
! read(1, *, iostat=errorLevel) value
! if (errorLevel /= 0) exit
! i=i+1
! if (i == 1) then
! max=value
! min=value
! write(maxRow,6) i
! write(minRow,6) i
! 6 format (I2)
! else
! if (value > max) then
! max=value
! write(maxRow,6) i
! else if (value < min) then
! min=value
! write(minRow,6) i
! else if (abs(value-max) < 1 ) then
! write(str,4) i, maxRow
! maxRow=str
! else if (abs(value-min) < 1) then
! write(str,4) i, minRow
! minRow=str
! end if
! 4 format (I2, ',', A10)
! end if
! write(*,3) i, maxRow, max, minRow, min
! 3 format (1X, "第", I2, "次读取,文件在第", A14, "行取到最大值为:"&
! &, F8.1, ",在第", A14, "行取到最小值为:", F8.1)
! end do
! write(*,2) maxRow, max, minRow, min
! 2 format (1X, "文件在第", A20, "行取到最大值为:", F8.1, ",在第", A20, "行取到最小值为:", F8.1)
! end program name
! 2021:04:14 16:33:55 5.6.3 5-27
! program name
! implicit none
! ! 以只读形式打开旧文件
! ! j=1
! ! DO
! ! 读取第j行字符并赋值给字符变量1长度小于133
! ! IF 错误等级<0 退出循环
! ! IF 错误等级>0 停止并报错
! ! DO i从1到字符变量1长度除去空格
! ! 抽取字符变量1第i个字符并赋值给一个长度为1的字符变量2
! ! IF 字符变量2不是逗号或者没有到达字符串末尾
! ! 跳过
! ! ELSE
! ! IF 到达了字符串末尾
! ! 结尾位数=i
! ! ELSE
! ! 结尾位数=i-1
! ! END IF
! ! sum=sum+实数1
! ! 计数1=计数1+1
! ! 字符变量3=空
! ! END IF
! ! END DO
! ! j=j+1
! ! END DO
! ! 平均值=sum/计数1
! integer :: i, j, k, errorLevel, valueStart, valueEnd
! real :: sum, value, average
! character(len=128) :: allValue, selectValue, readValue
! open (unit=1, file='content', status='old', action='read', iostat=errorLevel)
! if (errorLevel > 0) stop "读取文件出错"
! j=1
! k=0
! valueStart=1
! do
! read(1, '(A128)', iostat=errorLevel) allValue
! ! write(*,*) allValue
! if (errorLevel < 0) exit
! if (errorLevel > 0) stop "读取第j行出错"
! ! write(*,*) "读取第", j, "行"
! do i=1, len_trim(allValue), 1
! selectValue=allValue(i:i)
! ! write(*,*) "读取第", j, "行", "第", i, "列"
! if ( .not. ( trim(selectValue) == ',' .or. i == len_trim(allValue)) ) then
! ! ! readValue=trim(readValue) // trim(selectValue)
! ! ! write(*,*) '1', readValue
! ! else if ( trim(selectValue) == ' ') then
! ! ! write(*,*) '2', readValue
! cycle
! else
! if ( i == len_trim(allValue) ) then
! valueEnd=i
! else
! valueEnd=i-1
! end if
! readValue=allValue(valueStart:valueEnd)
! read(readValue, '(F5.1)', iostat=errorLevel) value
! if (errorLevel > 0) stop "第j行第i列附件的字符非合法数值请检查"
! sum=sum+value
! k=k+1
! ! write(*,*) '3', readValue
! readValue=''
! valueStart=i+1
! end if
! end do
! j=j+1
! end do
! average=sum/k
! write(*,2) k, sum, average
! 2 format (1X, "共计算", I3, "个数值,总和为", F5.1, ",平均值大小为", F5.1)
! close (unit=1)
! end program name
! 2021:04:14 17:31:01 一个用于读取文件中所有数值的程序案例
! program name
! ! =============================================================
! ! 目的:
! ! 遍历一个文件内的所有变量(需要全部是实数或整数)
! ! 修订记录:
! ! 日期 编程者 改动描述
! ! =================== ============= ======================
! ! 2021-04-14 17:46:57 Sola 编写源代码并校正格式
! ! =============================================================
! implicit none
! ! 数据字典
! ! 结构需要
! integer :: i ! 控制读取字符所在位置
! integer :: errorLevel ! 检查错误信息
! integer :: valueStart ! 读取数值开始位置
! integer :: valueEnd ! 读取数值结束位置
! real :: value ! 读取的数值内容
! character(len=128) :: allValue ! 所在行字符内容
! character(len=128) :: selectValue ! 读取所在行第i个字符内容
! character(len=128) :: readValue ! 读取的字符内容
! ! 使用者自定义
! ! 声明常量
! REAL, PARAMETER :: PI=3.14159265 ! PI值
! REAL, PARAMETER :: e=2.718281828459 ! 自然对数
! ! 声明变量
! ! 变量初始化
! valueStart=1
! ! 打开文件
! open (unit=1, file='content', status='old', action='read', iostat=errorLevel)
! if (errorLevel > 0) stop "读取文件出错"
! ! 遍历数值
! do
! read(1, '(A128)', iostat=errorLevel) allValue ! 读取行内容
! if (errorLevel < 0) exit ! 如果到达最后一行, 退出循环
! if (errorLevel > 0) stop "读取行出错" ! 读取行内容出错, 退出程序
! ! 遍历行内字符
! do i=1, len_trim(allValue), 1
! selectValue=allValue(i:i) ! 读取第i个字符
! if ( .not. ( trim(selectValue) == ',' .or. i == len_trim(allValue)) ) then
! cycle ! 如果不是逗号或到达末尾, 则跳过此次循环
! else ! 如果是逗号或到达末尾
! if ( i == len_trim(allValue) ) then
! valueEnd=i ! 如果是到达末尾, 则数值结束位置为i
! else
! valueEnd=i-1 ! 如果并未达到末尾, 则数值结束位置为i-1
! end if
! readValue=allValue(valueStart:valueEnd) ! 读取当前数值
! read(readValue, '(F5.1)', iostat=errorLevel) value ! 将当前数值赋值给一个实数
! if (errorLevel > 0) stop "存在非合法数值,请检查" ! 赋值存在错误, 退出程序
! valueStart=i+1 ! 下一次数值的开始位置为i+1
! end if
! end do
! valueStart=1 ! 开始新一行, 并将数值开始位置重置
! end do
! close (unit=1) ! 关闭文件
! end program name
! 2021:04:14 17:56:25 5.6.3 5-28
! program name
! ! =============================================================
! ! 目的:
! ! 遍历一个文件内的所有变量(需要全部是实数或整数)
! ! 修订记录:
! ! 日期 编程者 改动描述
! ! =================== ============= ======================
! ! 2021-04-14 17:46:57 Sola 编写源代码并校正格式
! ! 2021:04:14 17:57:21 Sola 将弧度转化为角度
! ! =============================================================
! implicit none
! ! 数据字典
! ! 结构需要
! integer :: i ! 控制读取字符所在位置
! integer :: errorLevel ! 检查错误信息
! integer :: valueStart ! 读取数值开始位置
! integer :: valueEnd ! 读取数值结束位置
! real :: value ! 读取的数值内容
! character(len=128) :: allValue ! 所在行字符内容
! character(len=128) :: selectValue ! 读取所在行第i个字符内容
! character(len=128) :: readValue ! 读取的字符内容
! ! 使用者自定义
! ! 声明常量
! REAL, PARAMETER :: PI=3.14159265 ! PI值
! REAL, PARAMETER :: e=2.718281828459 ! 自然对数
! ! 声明变量
! real :: angle ! 角度
! real :: radian ! 弧度
! integer :: angleDegree ! 度
! integer :: angleMinute ! 分
! integer :: angleSecond ! 秒
! ! 变量初始化
! valueStart=1
! ! 打开文件
! open (unit=1, file='content', status='old', action='read', iostat=errorLevel)
! if (errorLevel > 0) stop "读取文件出错"
! ! 遍历数值
! do
! read(1, '(A128)', iostat=errorLevel) allValue ! 读取行内容
! if (errorLevel < 0) exit ! 如果到达最后一行, 退出循环
! if (errorLevel > 0) stop "读取行出错" ! 读取行内容出错, 退出程序
! ! 遍历行内字符
! do i=1, len_trim(allValue), 1
! selectValue=allValue(i:i) ! 读取第i个字符
! if ( .not. ( trim(selectValue) == ',' .or. i == len_trim(allValue)) ) then
! cycle ! 如果不是逗号或到达末尾, 则跳过此次循环
! else ! 如果是逗号或到达末尾
! if ( i == len_trim(allValue) ) then
! valueEnd=i ! 如果是到达末尾, 则数值结束位置为i
! else
! valueEnd=i-1 ! 如果并未达到末尾, 则数值结束位置为i-1
! end if
! readValue=allValue(valueStart:valueEnd) ! 读取当前数值
! read(readValue, '(F10.6)', iostat=errorLevel) radian ! 将当前数值赋值给一个实数
! if (errorLevel > 0) stop "存在非合法数值,请检查" ! 赋值存在错误, 退出程序
! angle=radian/PI*360
! angleDegree=int(angle)
! angleMinute=int((angle-real(angleDegree))*60)
! angleSecond=nint((angle-real(angleDegree)-real(angleMinute)/60)*60*60)
! write(*,2) radian, angleDegree, angleMinute, angleSecond
! 2 format (1X, F10.6, " 转换为角度为", I4, "度 ", I2, "分 ", I2, "秒")
! valueStart=i+1 ! 下一次数值的开始位置为i+1
! end if
! end do
! valueStart=1 ! 开始新一行, 并将数值开始位置重置
! end do
! close (unit=1) ! 关闭文件
! end program name
! 2021:04:14 20:02:17 标准程序格式
! program name
! ! =============================================================
! ! 目的:
! !
! ! 修订记录:
! ! 日期 编程者 改动描述
! ! =================== ============= ======================
! ! =============================================================
! implicit none
! ! 数据字典
! ! 声明常量
! REAL, PARAMETER :: PI=3.14159265 ! PI值
! REAL, PARAMETER :: e=2.718281828459 ! 自然对数
! ! 声明变量
! ! 变量初始化
! end program name
! 2021:04:14 20:02:17 5.6.3 5-31
! program name
! ! =============================================================
! ! 目的:
! ! 天线放大率程式
! ! 修订记录:
! ! 日期 编程者 改动描述
! ! =================== ============= ======================
! ! 2021:04:14 20:05:37 Sola 编写源代码
! ! =============================================================
! implicit none
! ! 数据字典
! ! 声明常量
! REAL, PARAMETER :: PI=3.14159265 ! PI值
! REAL, PARAMETER :: e=2.718281828459 ! 自然对数
! ! 声明变量
! real :: G ! 天线放大率
! integer :: angle ! 角度
! real :: radian ! 弧度
! ! 变量初始化
! g=0
! radian=0
! angle=0
! write(*,1)
! 1 format (1X, "Form. 天线放大率与角度"/&
! &1X, T4, "radian", T15, "天线放大率"/&
! &1X, T2, "==========", T15, "==========")
! do angle=0,90,1
! radian=angle/360.*PI
! if ( (radian-0) < 0.01 ) then
! g=abs(1)
! else
! g=abs(sin(6*radian)/(6*radian))
! end if
! write(*,2) radian, G
! 2 format (1X, T3, F8.6, T16, F8.6)
! end do
! end program name
! 2021:04:14 22:45:42 5.6.3 5-32
! program name
! ! =============================================================
! ! 目的: 计算发动机输出功率
! !
! ! 修订记录:
! ! 日期 编程者 改动描述
! ! =================== ============= ======================
! ! 2021:04:14 22:46:13 Sola 编写源代码
! ! =============================================================
! implicit none
! ! 数据字典
! ! 声明常量
! REAL, PARAMETER :: PI=3.14159265 ! PI值
! REAL, PARAMETER :: e=2.718281828459 ! 自然对数
! ! 声明变量
! real :: p ! 功率 瓦特
! real :: t_ind ! 转矩
! real :: w_m ! 角速度 rad/s
! integer :: t ! 时间 1/4s
! ! 变量初始化
! write(*,1)
! 1 format (1X, "Form. 发动机随时间变化输出功率变化情况"/&
! &1X, T4, "Time(s)", T20, "P(w)"/&
! &1X, T1, "===========", T15, "===============")
! do t=0,40,1
! t_ind=10*e**(-0.25*0.25*t)
! w_m=377*(1-e**(-0.25*0.25*t))
! p=t_ind*w_m
! write(*,2) t*0.25, p
! 2 format (1X, T5, F5.2, T17, F10.5)
! end do
! end program name
! 2021:04:14 23:00:23 5.6.3 5-33 5-34
! program name
! ! =============================================================
! ! 目的: 计算轨道
! !
! ! 修订记录:
! ! 日期 编程者 改动描述
! ! =================== ============= ======================
! ! 2021:04:14 23:00:53 Sola 编写源代码
! ! 2021:04:14 23:50:44 Sola 增加新题目的功能
! ! =============================================================
! implicit none
! ! 数据字典
! ! 声明常量
! REAL, PARAMETER :: PI=3.14159265 ! PI值
! REAL, PARAMETER :: e=2.718281828459 ! 自然对数
! REAL, PARAMETER :: r_earth=6.371E3 ! 地球半径
! ! 声明变量
! real :: r ! 卫星距离地球中心的距离 km
! real :: p ! 确定轨道大小的参数
! real :: x ! 轨道离心率的参数
! real :: distanceMax ! 轨道最远距离 km
! real :: distanceMin ! 轨道最近距离 km
! integer :: errorLevel ! 错误参数
! integer :: i ! 循环用变量
! ! 变量初始化
! p=10000
! write(*,1)
! 1 format (1X, "Form. 卫星轨道信息一览表"/&
! &1X, " ε min(km) max(km)"/&
! &1X, "===== ========= =========")
! ! open (unit=2, status='scratch', iostat=errorLevel)
! ! write(2,'("0"/"0.25"/"0.5")')
! ! rewind (unit=2)
! ! do i = 1,3
! ! read(2,*) x
! ! distanceMax=p/(1-x)
! ! distanceMin=p/(1+x)
! ! write(*,2) x, distanceMin, distanceMax
! ! 2 format (1X, T2, F5.3, T9, F7.1, T19, F7.1)
! ! end do
! do i=0,10,1
! x=i*0.05
! distanceMax=p/(1-x)-r_earth
! distanceMin=p/(1+x)-r_earth
! write(*,2) x, distanceMin, distanceMax
! 2 format (1X, T2, F5.3, T9, F7.1, T19, F7.1)
! end do
! end program name
! 2021:04:15 00:39:05 5.6.3 5-35
! program name
! ! =============================================================
! ! 目的: 动态修改格式描述符
! !
! ! 修订记录:
! ! 日期 编程者 改动描述
! ! =================== ============= ======================
! ! 2021:04:15 00:39:50 Sola 编写源代码
! ! =============================================================
! implicit none
! ! 数据字典
! ! 声明常量
! REAL, PARAMETER :: PI=3.14159265 ! PI值
! REAL, PARAMETER :: e=2.718281828459 ! 自然对数
! ! 声明变量
! integer :: errorLevel ! 错误代码
! real :: x1, x2, x3, x4 ! 用于保存读取到的变量
! integer :: i ! 循环参数
! character(len=8) :: varType ! 输出格式
! ! 变量初始化
! open (unit=1, status="scratch", iostat=errorLevel)
! if (errorLevel /= 0) stop "Open file error!"
! write(1,1)
! 1 format("0.00012, -250., 6.02E23, -0.012"/&
! &"0.0, 12345.6, 1.6E-19, -1000.")
! rewind(unit=1)
! do i=1,2
! read(1,*) x1, x2, x3, x4
! if ( x1 == 0 .or. ( 0.01 <= abs(x1) .and. 1000.0 >= abs(x1) ) ) then
! varType='(F14.6)'
! else
! varType='(ES14.6)'
! end if
! write(*,trim(varType)) x1
! if ( x2 == 0 .or. ( 0.01 <= abs(x2) .and. 1000.0 >= abs(x2) ) ) then
! varType='(F14.6)'
! else
! varType='(ES14.6)'
! end if
! write(*,trim(varType)) x2
! if ( x3 == 0 .or. ( 0.01 <= abs(x3) .and. 1000.0 >= abs(x3) ) ) then
! varType='(F14.6)'
! else
! varType='(ES14.6)'
! end if
! write(*,trim(varType)) x3
! if ( x4 == 0 .or. ( 0.01 <= abs(x4) .and. 1000.0 >= abs(x4) ) ) then
! varType='(F14.6)'
! else
! varType='(ES14.6)'
! end if
! write(*,trim(varType)) x4
! end do
! end program name
! 2021-04-15 01:14:04 5.6.3 5-36
! program name
! ! =============================================================
! ! 目的:
! ! 最小二乘法回归并计算相关系数如果相关系数小于0.3,发出警告
! ! 修订记录:
! ! 日期 编程者 改动描述
! ! =================== ============= ======================
! ! 2021-04-15 01:12:35 Sola 编写源代码
! ! =============================================================
! implicit none
! ! 数据字典
! ! 声明常量
! REAL, PARAMETER :: PI=3.14159265 ! PI值
! REAL, PARAMETER :: e=2.718281828459 ! 自然对数
! ! 声明变量
! real :: x, y ! 坐标xy
! integer :: errorLevel ! 错误代码
! real :: m, b ! 拟合斜率和截距
! real :: x_bar, y_bar ! xy均值
! real :: r ! 相关系数
! real :: x_sum, y_sum ! xy总和
! real :: x2_sum, xy_sum, y2_sum ! 各种参数
! integer :: i ! 循环变量
! ! 变量初始化
! x_sum=0
! y_sum=0
! x2_sum=0
! y2_sum=0
! xy_sum=0
! i=0
! ! 输入数据
! open (unit=1, status='scratch', iostat=errorLevel)
! if (errorLevel /= 0) stop "Error!"
! write(1,1)
! 1 format("1.1, 1.01"/&
! &"2.2, 2.30"/&
! &"3.3, 3.05"/&
! &"4.4, 4.28"/&
! &"5.5, 5.75"/&
! &"6.6, 6.48"/&
! &"7.7, 7.84")
! rewind(unit=1)
! ! 计算参数
! do
! read(1,'(F10.4,F10.4)', iostat=errorLevel) x, y
! if (errorLevel<0) exit
! if (errorLevel>0) stop "Warning: Error!"
! x_sum=x_sum+x
! y_sum=y_sum+y
! x2_sum=x2_sum+x**2
! y2_sum=y2_sum+y**2
! xy_sum=xy_sum+x*y
! i=i+1
! end do
! x_bar=x_sum/real(i)
! y_bar=y_sum/real(i)
! m=(xy_sum-x_sum*y_bar)/(x2_sum-x_sum*x_bar)
! b=y_bar-m*x_bar
! r=(real(i)*xy_sum-x_sum*y_sum)/sqrt((real(i)*x2_sum-x_sum**2)*(real(i)*y2_sum-y_sum**2))
! ! 输出结果
! if (abs(r)<0.3) write(*,*) 'Warning: r is too low!'
! write(*,2) m, b, r
! 2 format(1X, "方程拟合的结果为: y = ", F5.2, " x + ( ", F5.2, " ) , 相关系数为: ", F5.3)
! end program name
! 2021-04-15 01:14:04 5.6.3 5-37
! program name
! ! =============================================================
! ! 目的: 计算飞行器旋转半径
! !
! ! 修订记录:
! ! 日期 编程者 改动描述
! ! =================== ============= ======================
! ! 2021-04-15 01:14:04 Sola 编写源代码
! ! =============================================================
! implicit none
! ! 数据字典
! ! 声明常量
! REAL, PARAMETER :: PI=3.14159265 ! PI值
! REAL, PARAMETER :: e=2.718281828459 ! 自然对数
! REAL, PARAMETER :: g=9.8 ! 重力加速度, g/s^2
! REAL, PARAMETER :: mach=340 ! 马赫, 声速, m/s
! ! 声明变量
! real :: a
! real :: v
! real :: r
! integer :: i
! ! 变量初始化
! i=0
! ! 输出数据
! write(*,1)
! 1 format(1X, "Form1. 飞行器转弯半径与飞行器速度关系表"/&
! &1X, " v(m/s) r(m) "/&
! &1X, "========== ======================")
! do i=5,20,1
! v=real(i)/10.*mach
! a=2*g
! r=v**2/a
! write(*,2) v, r
! 2 format(1X, T3, F8.1, T17, F17.3)
! end do
! write(*,3)
! 3 format(1X, "========== ======================"/&
! &/&
! &1X, "Form2. 飞行器转弯半径与向心加速度关系表"/&
! &1X, " a(m/s^2) r(m) "/&
! &1X, "========== ======================")
! do i=4,16,1
! a=real(i)*0.5*g
! v=0.85*mach
! r=v**2/a
! write(*,2) a, r
! end do
! write(*,4)
! 4 format(1X, "========== ======================")
! end program name
! ! 2021-04-15 01:14:04 测试
! program name
! implicit none
! real :: error(-3:0)
! error(-3)=0.00012
! error(-2)=0.0152
! error(-1)=0.0
! write(*,500) error
! 500 format(T6,"error = ",/,(3X,F6.4))
! end program name
! 2021-04-15 01:14:04 排序算法
! program name
! ! =============================================================
! ! 目的: 对输入数据进行排序
! ! 程序结构:
! ! 打开文件
! ! DO
! ! 读入数据赋值给数组对应位置, 并获取错误代码
! ! IF 错误代码 < 0 EXIT
! ! 记录数+1
! ! END DO
! ! DO i从1到记录数-1
! ! 最小值=数组(i)
! ! 最小值位置=i
! ! DO j从i+1到记录数
! ! IF 数组(j)<最小值 THEN
! ! 最小值=数组(j)
! ! 最小值位置=j
! ! END IF
! ! END DO
! ! IF 最小值位置/=i THEN
! ! 数组(最小值位置)=数组(i)
! ! 数组(i)=最小值
! ! END IF
! ! END DO
! ! 输出数组
! ! 修订记录:
! ! 日期 编程者 改动描述
! ! =================== ============= ======================
! ! 2021-04-15 01:14:04 Sola 编写源代码
! ! 2021-04-15 01:14:04 Sola 防止数据溢出
! ! 2021-04-15 09:48:33 Sola 避免错误数据
! ! =============================================================
! implicit none
! ! 数据字典
! ! 声明常量
! REAL, PARAMETER :: PI=3.14159265 ! PI值
! REAL, PARAMETER :: e=2.718281828459 ! 自然对数
! ! 声明变量
! integer, parameter :: arrayLength = 20 ! 数组长度
! real, dimension(arrayLength) :: array ! 定义数组
! integer :: errorLevel ! 错误代码
! integer :: i, j, k ! 循环参数
! integer :: minLocate ! 最小值位置
! real :: min ! 最小值
! logical :: excess ! 数据溢出判断参数
! real :: temp ! 储存临时数值
! ! 变量初始化
! k=0
! i=0
! excess=.FALSE.
! open(unit=1, status='scratch')
! write(1,1)
! 1 format(1X, "123.5"/&
! &1X, "563"/&
! &1X, "586.3"/&
! &1X, "12"/&
! &1X, "0"/&
! &1X, "-l99"/&
! &1X, "67"/&
! &1X, "24"/&
! &1X, "51"/&
! &1X, "999"/&
! &1X, "30"/&
! &1X, "-1a11"/&
! &1X, "666"/&
! &1X, "787"/&
! &1X, "720"/&
! &1X, "98u0"/&
! &1X, "985")
! rewind(unit=1)
! do
! read(1,*,iostat=errorLevel) temp
! if (errorLevel < 0) exit
! i=i+1
! if (errorLevel > 0) then
! write(*,3) i
! 3 format(1X, "程序在输入数据的第", I3, "行读取到非法输入,&
! &请检查数据源,已跳过该数据")
! ! 3 format(1X, I3)
! cycle
! end if
! if (k < arrayLength) then
! k=k+1
! array(k)=temp
! else
! excess=.TRUE.
! exit ! 从程序一般只有一个出口来看这边最好不要有exit
! end if
! end do
! if ( .not. excess ) then
! do i=1,k-1
! minLocate=i
! do j=i+1,k
! if (array(j) < array(minLocate)) then
! minLocate=j
! end if
! end do
! if (minLocate /= i) then
! min=array(minLocate)
! array(minLocate)=array(i)
! array(i)=min
! end if
! end do
! write(*,2) array
! 2 format(10(F7.2, 1X))
! else
! write(*,*) '输入参数过多!'
! end if
! close(unit=1)
! end program name

350
第6章习题.f90 Normal file
View File

@ -0,0 +1,350 @@
! 2021-04-15 01:14:04 6.7.3 6-5(c)
! program name
! !
! ! 目的:
! ! 测试数组之间比较会输出什么,最后确认会一个一个比较,然后输出一个数组
! !
! ! 修订记录:
! ! 日期 编程者 改动描述
! ! =================== ============= ======================
! ! 2021-04-15 01:14:04 Sola 编写源代码
! !
! ! 程序结构:
! !
! implicit none
! ! 数据字典
! ! 声明常量
! REAL, PARAMETER :: PI=3.14159265 ! PI值
! REAL, PARAMETER :: e=2.718281828459 ! 自然对数
! INTEGER, PARAMETER :: arrayLength=6 ! 数组基准长度
! ! 声明变量
! integer, dimension(arrayLength) :: a, b ! 使用的数组
! ! 变量初始化
! a = (/1,-3,0,-5,-9,3/)
! b = (/-6,6,0,5,2,-1/)
! write(*,*) a > b
! ! 数据输入
! ! 运算过程
! ! 结果输出
! end program name
! 2021-04-15 01:14:04 6.7.3 6-10 6-11
! program name
! !
! ! 目的:
! ! 极坐标转换为直角坐标; 直角坐标转化为极坐标
! !
! ! 修订记录:
! ! 日期 编程者 改动描述
! ! =================== ============= ======================
! ! 2021-04-15 01:14:04 Sola 编写源代码
! ! 2021-04-15 01:14:04 Sola 增加反向转换功能
! !
! ! 程序结构:
! !
! implicit none
! ! 数据字典
! ! 声明常量
! REAL, PARAMETER :: PI=3.14159265 ! PI值
! REAL, PARAMETER :: e=2.718281828459 ! 自然对数
! INTEGER, PARAMETER :: arrayLength=2 ! 数组基准长度
! ! 声明变量
! integer :: errorLevel
! real, dimension(arrayLength) :: polar, reat ! 极坐标数组、直角坐标数组
! ! 变量初始化
! open(unit=1, status='scratch')
! write(1,1)
! 1 format(1X, "5, -36.87"/&
! &1X, "10, 45"/&
! &1X, "25, 233.13")
! rewind(unit=1)
! ! 数据输入
! write(*,3)
! 3 format(1X, " Table of 6-10 "/&
! &1X, " x y "/&
! &1X, "======= =======")
! do
! read(1,*,iostat=errorLevel) polar(1), polar(2)
! if (errorLevel/=0) exit
! reat(1)=polar(1)*cos(polar(2)/360.*PI)
! reat(2)=polar(1)*sin(polar(2)/360.*PI)
! write(*,2) reat(1), reat(2)
! 2 format(1X, T2, F6.2, T10, F6.2)
! end do
! rewind(unit=1)
! write(1,4)
! 4 format(1X, "3, -4"/&
! &1X, "5, 5"/&
! &1X, "-5, 12")
! rewind(unit=1)
! write(*,5)
! 5 format(1X/&
! &1X, " Table of 6-11 "/&
! &1X, " V θ "/&
! &1X, "======= =======")
! do
! read(1,*,iostat=errorLevel) reat(1), reat(2)
! if (errorLevel/=0) exit
! polar(1)=sqrt(reat(1)**2+reat(2)**2)
! polar(2)=atan(reat(2)/reat(1))
! write(*,2) polar(1), polar(2)
! ! write(*,*) atan2(reat(2),reat(1))
! end do
! ! 运算过程
! ! 结果输出
! end program name
! 2021-04-15 01:14:04 6.7.3 6-12
! program name
! !
! ! 目的:
! ! 计算一组数据中正数、负数和0的个数
! !
! ! 修订记录:
! ! 日期 编程者 改动描述
! ! =================== ============= ======================
! ! 2021-04-15 01:14:04 Sola 编写源代码
! !
! ! 程序结构:
! !
! implicit none
! ! 数据字典
! ! 声明常量
! REAL, PARAMETER :: PI=3.14159265 ! PI值
! REAL, PARAMETER :: e=2.718281828459 ! 自然对数
! INTEGER, PARAMETER :: arrayLength=20 ! 数组基准长度
! ! 声明变量
! real, dimension(-50:50) :: values
! integer :: positiveSum, zeroSum, negativeSum ! 正数、零、负数的个数
! integer :: i ! 循环参数
! ! 变量初始化
! positiveSum=0
! zeroSum=0
! negativeSum=0
! values=[(i, i=-50,50)]
! do i=-50,50
! if (values(i) > 0) then
! positiveSum=positiveSum+1
! else if (values(i) < 0) then
! negativeSum=negativeSum+1
! else
! zeroSum=zeroSum+1
! end if
! end do
! write(*,1) positiveSum, negativeSum, zeroSum
! 1 format(1X, "统计结果:输入数组中共有正数", I2, "个,负数", I2, "个,零", I2, "个")
! ! 数据输入
! ! 运算过程
! ! 结果输出
! end program name
! 2021-04-15 01:14:04 6.7.3 6-14
! program name
! !
! ! 目的:
! ! 6-14 计算点积
! ! 6-15 作用于物体的功率
! !
! ! 修订记录:
! ! 日期 编程者 改动描述
! ! =================== ============= ======================
! ! 2021-04-15 01:14:04 Sola 编写源代码
! ! 2021-04-15 01:14:04 Sola 计算作用于物体的功率
! !
! ! 程序结构:
! !
! implicit none
! ! 数据字典
! ! 声明常量
! REAL, PARAMETER :: PI=3.14159265 ! PI值
! REAL, PARAMETER :: e=2.718281828459 ! 自然对数
! INTEGER, PARAMETER :: arrayLength=3 ! 数组基准长度
! ! 声明变量
! real, dimension(arrayLength) :: array1, array2 ! 点积的两个矢量
! real, dimension(arrayLength) :: arrayResult ! 点积结果矢量
! real :: result ! 点积结果
! integer :: i ! 循环参数
! ! 变量初始化
! array1 = [4, 3, -2]
! array2 = [4, -2, 1]
! result=0
! arrayResult = array1*array2
! do i=1,arrayLength
! result=result+arrayResult(i)
! end do
! write(*,1) result
! ! 1 format(1X, "两矢量的点积结果为 ", F6.2)
! 1 format(1X, "作用于物体的功率为 ", F6.2)
! ! 数据输入
! ! 运算过程
! ! 结果输出
! end program name
! program name
! !
! ! 目的:
! ! 6.7.3 6-16 计算差积
! ! 6.7.3 6-17 计算绕轨道运行物体的速度
! !
! ! 修订记录:
! ! 日期 编程者 改动描述
! ! =================== ============= ======================
! ! 2021-04-15 01:14:04 Sola 编写源代码
! ! 2021-04-15 09:28:26 Sola 计算绕轨道运行物体的速度
! !
! ! 程序结构:
! !
! implicit none
! ! 数据字典
! ! 声明常量
! REAL, PARAMETER :: PI=3.14159265 ! PI值
! REAL, PARAMETER :: e=2.718281828459 ! 自然对数
! INTEGER, PARAMETER :: arrayLength=3 ! 数组基准长度
! ! 声明变量
! real, dimension(arrayLength) :: array1 ! 矢量1
! real, dimension(arrayLength) :: array2 ! 矢量2
! real, dimension(arrayLength) :: arrayResult ! 结果矢量
! real :: v ! 运行速度
! ! 变量初始化
! array1 = [5,-3,2]
! array2 = [2,3,4]
! arrayResult = array1((/2,3,1/))*array2((/3,1,2/))-array2((/2,3,1/))*array1((/3,1,2/))
! write(*,1) arrayResult
! 1 format(1X, "矢量V1与矢量V2的差积为", 3(1X, F6.2))
! array1 = [300000,400000,50000]
! array2 = [-6E-3,2E-3,9E-4]
! arrayResult = array1((/2,3,1/))*array2((/3,1,2/))-array2((/2,3,1/))*array1((/3,1,2/))
! v=(arrayResult(1)**2+arrayResult(2)**2+arrayResult(3)**2)**1./3.
! write(*,2) v
! 2 format(1X, "绕轨道运行物体的速度为:", F11.2, " m/s")
! ! 数据输入
! ! 运算过程
! ! 结果输出
! end program name
! program name
! !
! ! 目的:
! ! 集合的交集与并集运算
! !
! ! 修订记录:
! ! 日期 编程者 改动描述
! ! =================== ============= ======================
! ! 2021-04-15 10:05:11 Sola 编写源代码
! !
! ! 程序结构:
! !
! implicit none
! ! 数据字典
! ! 声明常量
! REAL, PARAMETER :: PI=3.14159265 ! PI值
! REAL, PARAMETER :: e=2.718281828459 ! 自然对数
! INTEGER, PARAMETER :: arrayLength=20 ! 数组基准长度
! ! 声明变量
! character(len=8), dimension(arrayLength) :: aggregateA! 集合A
! character(len=8), dimension(arrayLength) :: aggregateB! 集合B
! character(len=8), dimension(arrayLength) :: aggregateC! 集合C交集
! character(len=8), dimension(arrayLength) :: aggregateD! 集合D并集
! integer :: i, j, k ! 循环参数
! integer :: errorLevel ! 错误代码
! character(len=40) :: temp ! 临时保存
! ! 变量初始化
! i=0
! j=0
! k=0
! aggregateA='NaN'
! aggregateB='NaN'
! open(unit=1, status='scratch')
! open(unit=2, status='scratch')
! write(1,*) ' 0,1,-3,5,-11,6,8,11,17,15'
! write(2,*) ' 0,-1,3,6,-6,16,5,12,21'
! rewind(unit=1)
! rewind(unit=2)
! read(1,*,iostat=errorLevel) aggregateA
! read(2,*,iostat=errorLevel) aggregateB
! do i=1,arrayLength
! if (aggregateA(i) /= 'NaN') then
! if (any(aggregateA(i)==aggregateB)) then
! k=k+1
! aggregateC(k)=aggregateA(i)
! end if
! else
! exit
! end if
! end do
! write(*,'(1X, "集合A与集合B的交集为", 20(A3))') aggregateC(1:k)
! k=0
! do i=1,arrayLength
! if (aggregateA(i) /= 'NaN') then
! if (any(aggregateA(i) /= aggregateD)) then
! k=k+1
! aggregateD(k)=aggregateA(i)
! end if
! else
! exit
! end if
! end do
! do i=1,arrayLength
! if (aggregateB(i) /= 'NaN') then
! if (.not. any(aggregateB(i)==aggregateD(1:k))) then
! k=k+1
! aggregateD(k)=aggregateB(i)
! end if
! else
! exit
! end if
! end do
! write(*,'(1X, "集合A与集合B的并集为", 20(A4))') aggregateD(1:k)
! ! 数据输入
! ! 运算过程
! ! 结果输出
! end program name
! program name
! !
! ! 目的:
! ! 计算三维空间中两点间距离
! !
! ! 修订记录:
! ! 日期 编程者 改动描述
! ! =================== ============= ======================
! ! 2021-04-15 11:08:39 Sola 编写源代码
! !
! ! 程序结构:
! !
! implicit none
! ! 数据字典
! ! 声明常量
! REAL, PARAMETER :: PI=3.14159265 ! PI值
! REAL, PARAMETER :: e=2.718281828459 ! 自然对数
! INTEGER, PARAMETER :: arrayLength=3 ! 数组基准长度
! ! 声明变量
! real, dimension(arrayLength) :: pointA ! 点A坐标
! real, dimension(arrayLength) :: pointB ! 点B坐标
! real, dimension(arrayLength) :: arrayTemp ! 临时数组
! real :: distance ! 两点间距离
! real :: temp ! 临时变量
! integer :: i ! 循环参数
! ! 变量初始化
! pointA=[-1,4,6]
! pointB=[1,5,-2]
! temp=0
! arrayTemp=(pointA-pointB)**2
! do i=1,arrayLength
! temp=temp+arrayTemp(i)
! end do
! distance=sqrt(temp)
! write(*,1) distance
! 1 format(1X, "两点间距离为:", F6.2)
! ! 数据输入
! ! 运算过程
! ! 结果输出
! end program name

932
第7章习题.f90 Normal file
View File

@ -0,0 +1,932 @@
! ==============================================================================
! 通过 gfortran ./test.f90 -o ./run && ./run 运行
! 程序名:
! 习题
! 目的:
!
! 修订记录:
! 日期 编程者 改动描述
! =================== ============= =====================================
! 2021-04-16 19:59:35 Sola 7.3 1~4 编写源代码
! 2021-04-16 20:30:45 Sola 修改7.3 4的代码直接比较赋值不就好了
! 2021-04-16 21:28:46 Sola 测试下external语句的使用
! 2021-04-17 16:10:12 Sola 习题7-9b
! 2021-04-17 16:22:35 Sola 习题7-10
! 2021-04-17 16:51:53 Sola 习题7-14 随机数程序
! 2021-04-17 16:57:46 Sola 习题7-15 掷色子程序
! 2021-04-17 17:39:09 Sola 习题7-16 泊松分布
! 2021-04-17 18:01:03 Sola 习题7-18 计算双曲正弦值、余弦值、正切值
! 2021-04-17 18:49:40 Sola 习题7-19 向量叉积3维向量
! 2021-04-17 20:16:43 Sola 习题7-20 数组排序
! 2021-04-17 21:11:06 Sola 习题7-21 函数的最大值和最小值
! 2021-04-17 21:45:25 Sola 习题7-22 代入函数计算
! 2021-04-17 21:54:08 Sola 习题7-23 微分函数
! 2021-04-18 00:54:09 Sola 习题7-24 噪声值微分
! 2021-04-18 11:50:23 Sola 习题7-25 二进制运算(加减及进制转换)
! 2021-04-25 15:23:51 Sola 习题7-26 线性最小二乘拟合
! 2021-04-25 16:00:28 Sola 习题7-27 最小二乘拟合的相关系数
! 2021-04-25 16:07:05 Sola 习题7-28 生日问题
! 2021-04-25 17:42:55 Sola 习题7-29 经时计算
! 2021-04-25 21:04:53 Sola 习题7-30 使用计时器子程序
! 2021-04-25 21:49:32 Sola 习题7-31 估算无限序列
! 2021-04-25 22:45:24 Sola 习题7-32 使用子程序计算随机分布
! 2021-04-26 00:20:22 Sola 习题7-33 高斯(正态)分布
! 2021-04-26 01:43:23 Sola 习题7-34 引力
! 2021-04-26 01:54:59 Sola 习题7-35 堆排序, 了解有这么个玩意就成
! 程序结构:
!
! ==============================================================================
! 模块:
module MouName
implicit none
! 数据字典
! 声明常数
REAL, PARAMETER :: PI=3.14159265 ! PI值
REAL, PARAMETER :: e=2.718281828459 ! 自然对数
INTEGER, PARAMETER :: arrayLength=20 ! 数组基准长度
REAL, PARAMETER :: criticalZero=1.0E-30 ! 0的临界值
! 声明变量
! real function Function1(x)
! real function Function2(x)
! integer function Function3(n)
! logical function Function4(x,y)
real :: x, y
integer :: n
! 创建显式接口
contains
! 习题7.3 2
real function Function2(x)
implicit none
real, intent(in) :: x
Function2=(exp(x)-exp(-x))/(exp(x)+exp(-x))
end function Function2
! 习题7.3 3 计算阶乘
integer function Function3(n)
implicit none
! external :: Function3
integer, intent(in) :: n
integer :: i
Function3 = 1
do i=2,n
Function3 = Function3 * i
end do
end function Function3
! 习题7.3 4
logical function Function4(x, y)
implicit none
real, intent(in) :: x, y
! if ( x**2+y**2 > 1.0 ) then
! Function4 = .TRUE.
! else
! Function4 = .FALSE.
! end if
Function4 = x**2+y**2 > 1.0
end function Function4
! 测试用
subroutine Subroutine1(fun, x, result, errorLevel)
implicit none
real :: fun
! external :: fun
real, intent(in) :: x
real, intent(out) :: result
integer, intent(out) :: errorLevel
result = fun(x)
end subroutine Subroutine1
! 习题7-9 b
subroutine max_char(string, big)
implicit none
character(len=10), intent(in) :: string
character, intent(out) :: big
integer :: i
big = string(1:1)
do i = 2,10
if ( string(i:i) > big ) then
big = string(i:i)
end if
end do
end subroutine max_char
! 叉积运算函数
function VectorProduct_3(vectorX, vectorY)
implicit none
real, dimension(3) :: VectorProduct_3
real, dimension(3), intent(in) :: vectorX, vectorY
VectorProduct_3 = vectorX((/2,3,1/))*vectorY((/3,1,2/))-vectorY((/2,3,1/))*vectorX((/3,1,2/))
end function VectorProduct_3
! function VectorProduct_3(vectorX, vectorY)
! implicit none
! real, dimension(3) :: VectorProduct_3
! real, dimension(3), intent(in) :: vectorX, vectorY
! ! write(*,*) vectorX, vectorY
! ! VectorProduct_3=[1,1,1]
! VectorProduct_3 = vectorX((/2,3,1/))*vectorY((/3,1,2/))-vectorY((/2,3,1/))*vectorX((/3,1,2/))
! end function VectorProduct_3
! 随机数子程序
! subroutine random(ran, iseed)
! implicit none
! real, intent(in) :: iseed
! real, intent(out) :: ran
! real :: n
! if ( iseed = '' ) then
! iseed = 12345
! end if
! n = abs(iseed)
! n = mod(8121*n+28411,134456)
! ran = real(n)/134456
! end subroutine random
! 字符串二进制加法运算
function BinaryAddition(strInput1, strInput2, strLength)
implicit none
integer, intent(in) :: strLength
character(len=strLength), intent(in) :: strInput1, strInput2
character(len=strLength) :: BinaryAddition
integer :: i, j
j = 0
do i = 1, strLength
if ( (strInput1(i:i) /= '0' .and. strInput1(i:i) /= '1') &
&.or. (strInput2(i:i) /= '0' .and. strInput2(i:i) /= '1') ) stop "输入数据包含非法字符"
end do
do i = strLength, 1, -1
select case ( iachar(strInput1(i:i)) + iachar(strInput2(i:i)) + j )
case ( 96:96 )
BinaryAddition(i:i) = '0' ! 0+0
j = 0
case ( 97:97 )
BinaryAddition(i:i) = '1' ! 0+1, 1+0, 0+0+1
j = 0
case ( 98:98 )
BinaryAddition(i:i) = '0' ! 1+1, 1+0+1, 0+1+1
j = 1
case ( 99:99 )
BinaryAddition(i:i) = '1' ! 1+1+1
j = 1
end select
end do
end function BinaryAddition
! 字符串二进制减法运算
function BinarySubtraction(strInput1, strInput2, strLength)
implicit none
integer, intent(in) :: strLength
character(len=strLength), intent(in) :: strInput1, strInput2
character(len=strLength) :: BinarySubtraction
integer :: i, j
j = 0
do i = 1, strLength
if ( (strInput1(i:i) /= '0' .and. strInput1(i:i) /= '1') &
&.or. (strInput2(i:i) /= '0' .and. strInput2(i:i) /= '1') ) stop "输入数据包含非法字符"
end do
do i = strLength, 1, -1
select case ( iachar(strInput1(i:i)) - iachar(strInput2(i:i)) + j )
case ( 0:0 )
BinarySubtraction(i:i) = '0' ! 0-0, 1-1, 1-0-1
j = 0
case ( 1:1 )
BinarySubtraction(i:i) = '1' ! 1-0
j = 0
case ( -1:-1 )
BinarySubtraction(i:i) = '1' ! 0-1, 0-0-1, 1-1-1
j = -1
case ( -2:-2 )
BinarySubtraction(i:i) = '0' ! 0-1-1
j = -1
end select
end do
end function BinarySubtraction
! 字符串二进制转整型十进制
integer function BaseConversion_2To10(Base2Str, strLength)
implicit none
integer, intent(in) :: strLength
character(len=strLength), intent(in) :: Base2Str
integer :: i, value
BaseConversion_2To10 = 0
do i = 2, strLength
read(Base2Str(i:i),*) value
BaseConversion_2To10 = BaseConversion_2To10 + value*2**(strLength-i)
end do
if ( Base2Str(1:1) == '1' ) BaseConversion_2To10 = BaseConversion_2To10 - 2**(strLength-1)
end function BaseConversion_2To10
! 整数型十进制转字符串二进制
function BaseConversion_10To2(Base10Int, strLength)
implicit none
integer, intent(in) :: Base10Int, strLength
character(len=strLength) :: BaseConversion_10To2, oneBase2
integer :: i, value
value = abs(Base10Int)
if ( value > 2**(strLength-1) ) stop "数值越界"
do i = strLength, 1, -1
if ( mod(value, 2) == 1 ) then
BaseConversion_10To2(i:i) = '1'
else
BaseConversion_10To2(i:i) = '0'
end if
value = value / 2
end do
if ( Base10Int < 0 ) then
do i = 1, strLength
if ( BaseConversion_10To2(i:i) == '1' ) then
BaseConversion_10To2(i:i) = '0'
else
BaseConversion_10To2(i:i) = '1'
end if
end do
do i = 1, strLength-1
oneBase2(i:i) = '0'
end do
oneBase2(strLength:strLength) = '1'
BaseConversion_10To2 = BinaryAddition(BaseConversion_10To2, oneBase2, strLength)
end if
end function BaseConversion_10To2
end module MouName
! ==============================================================================
! 主程序:
program ProName
use MouName
implicit none
! 数据字典
! 声明常量
! 声明变量
! real, external :: Function1
real :: Function1
real :: result
integer :: errorLevel
! 变量初始化
! write(*,*) '1. 输入x=2则f(x)= ', Function1(2.)
! write(*,*) '2. 输入x=3则tanh(x)= ', Function2(3.)
! write(*,*) '3. 11的阶乘为 ', Function3(11)
! write(*,*) '4. 输入x=3y=4则其平方和是否大于1.0?结果为:', Function4(3., 4.)
! call Subroutine1(Function1, 3., result, errorLevel)
! write(*,*) result
! call Exercises7_9
! call Exercises7_10
! call Exercises7_15
! call Exercises7_16
! call Exercises7_18
! call Exercises7_19
! call Exercises7_20
! call Exercises7_21
! call Exercises7_23
! call Exercises7_25
! call Exercises7_26
! call Exercises7_28
! call Exercises7_29
! call Exercises7_31
! call Exercises7_32
! call Exercises7_33
! call Exercises7_34
end program ProName
! ==============================================================================
! 子程序
! subroutine SubName(varName1,varName2)
! use MouName
! implicit none
! Type, intent(inout) :: varName
! end subroutine SubName
! ==============================================================================
! 函数
! function FunName(varName1,varName2)
! use MouName
! implicit none
! end function FunName
! ==============================================================================
real function Function1(x)
implicit none
! 数据字典
real, intent(in) :: x
Function1 = (x-1)/(x+1)
end function Function1
! 习题7-9 b 最终结果会出现警告,但可以运行,结果也是正确的,不知道是不是巧合
subroutine Exercises7_9
use MouName
implicit none
character(len=10) :: str = '1AbHz05Z'
character :: largest
call max_char (str, largest)
write(*,100) str, largest
100 format(' The largest character in ', A, ' is ', A)
end subroutine Exercises7_9
! 习题7-10
module my_constants
implicit none
real, parameter :: PI_1 = 3.141593
real, parameter :: G_1 = 9.81
end module my_constants
subroutine Exercises7_10
! implicit none
use my_constants
write(*,*) 'SIN(2*PI) = ', sin(2.*PI_1)
! G_1 = 17.
end subroutine Exercises7_10
! 习题7-14
module ran001
implicit none
integer :: n = 12345
end module ran001
subroutine seed0(iseed)
use ran001
implicit none
real, intent(in) :: iseed
n = abs(iseed)
end subroutine seed0
subroutine random(ran)
use ran001
implicit none
real, intent(inout) :: ran
n = mod(8121*n+28411,134456)
ran = real(n)/134456
end subroutine random
subroutine Exercises7_14
implicit none
real :: randomSeed = 123456
real :: randomValue
integer :: i
call seed0(randomSeed)
do i = 1,10
call random(randomValue)
randomValue = randomValue*2.-1
write(*,*) randomValue
end do
end subroutine Exercises7_14
! 习题7-15
subroutine Exercises7_15
implicit none
real :: randomSeed = 123456
real :: randomValue, sum = 0
integer :: i, point
integer, dimension(6) :: pointSum
call seed0(randomSeed)
pointSum = 0
do i = 1,1000000
call random(randomValue)
point = int(randomValue*6+1)
! write(*,*) '你掷到了数字', point
pointSum(point) = pointSum(point) + 1
end do
write(*,*) '各点数计数分别为:', (pointSum(i), ',', i = 1, 6)
end subroutine
! 习题7-16
subroutine Exercises7_16
implicit none
real :: countPerMinute, time, probability, PoissonDistribution
integer :: k
countPerMinute=1.6
time=1.
do k = 0, 5
probability = PoissonDistribution(k, time, countPerMinute)
write(*,*) '一分钟内有', k, '辆车经过的可能性为', probability
end do
end subroutine Exercises7_16
! 泊松分布函数
real function PoissonDistribution(k, t, countBar)
implicit none
integer, intent(in) :: k
real, intent(in) :: t, countBar
integer :: i, kFactorial
kFactorial = 1
do i = 2, k
kFactorial = kFactorial*i
end do
PoissonDistribution = exp(-countBar*t)*(countBar*t)**k/real(kFactorial)
end function PoissonDistribution
! 习题7-18
subroutine Exercises7_18
implicit none
real :: x, FunSinh, FunCosh, FunTanh
integer :: i
real, dimension(11) :: numList=[-2.0,-1.5,-1.0,-0.5,-0.25,0.0,0.25,0.5,1.0,1.5,2.0]
x = 1.2
write(*,*) '双曲正弦值:计算结果为:', FunSinh(x), '验证值为:', sinh(x)
write(*,*) '双曲余弦值:计算结果为:', FunCosh(x), '验证值为:', cosh(x)
write(*,*) '双曲正切值:计算结果为:', FunTanh(x), '验证值为:', tanh(x)
write(*,*)
write(*,1) 'Num ', numList
write(*,*) '==== ======== ======== ======== ======== ======== &
&======== ======== ======== ======== ======== ========'
write(*,1) 'Sinh', (FunSinh(numList(i)), i = 1, 11)
write(*,1) 'CosH', (FunCosh(numList(i)), i = 1, 11)
write(*,1) 'Tanh', (FunTanh(numList(i)), i = 1, 11)
1 format(1X, A4, 11(1X, F8.5))
end subroutine Exercises7_18
! 双曲正弦
real function FunSinh(x)
implicit none
real, intent(in) :: x
FunSinh = (exp(x)-exp(-x))/2
end function FunSinh
! 双曲余弦
real function FunCosh(x)
implicit none
real, intent(in) :: x
FunCosh = (exp(x)+exp(-x))/2
end function FunCosh
! 双曲正切
real function FunTanh(x)
implicit none
real, intent(in) :: x
FunTanh = (exp(x)-exp(-x))/(exp(x)+exp(-x))
end function FunTanh
! 习题7-19 向量叉积(三维向量)
subroutine Exercises7_19
use MouName
implicit none
real, dimension(3) :: array1 ! 矢量1
real, dimension(3) :: array2 ! 矢量2
real, dimension(3) :: arrayResult ! 结果矢量
array1 = [-2.,4.,0.5]
array2 = [0.5,3.,2.]
write(*,1) VectorProduct_3(array1, array2)
1 format(1X, "矢量V1与矢量V2的差积为", 3(1X, F6.2))
end subroutine Exercises7_19
! 叉积运算子程序,为啥子程序能运行,函数不可以,一定要放到模组里,,,是真的恶心,不然就会被当作调用数组而不是调用函数
! subroutine VectorProduct_3(vectorX, vectorY, arrayResult, n)
! implicit none
! integer :: n
! real, intent(in), dimension(n) :: vectorX, vectorY
! real, intent(out), dimension(n) :: arrayResult
! arrayResult = vectorX((/2,3,1/))*vectorY((/3,1,2/))-vectorY((/2,3,1/))*vectorX((/3,1,2/))
! end subroutine VectorProduct_3
! 习题7-20 数组排序
subroutine Exercises7_20
implicit none
integer, parameter :: arrayLength = 9
real, dimension(arrayLength) :: arr1, arr2
arr1 = (/1.,11.,-6.,17.,-23.,0.,5.,1.,-1./)
arr2 = (/31.,101.,36.,-17.,0.,10.,-8.,-1.,-1./)
call ArraySort(arr1, arr2, arrayLength)
write(*,1) 'arr1', arr1
write(*,1) 'arr2', arr2
1 format(1X, A, 9(F7.2, 1X))
end subroutine Exercises7_20
! 习题7-20 数组排序
subroutine ArraySort(arrayBase, arrayEntourage, n)
implicit none
integer :: n
real, intent(inout), dimension(n) :: arrayBase, arrayEntourage
integer :: i, j, maxPosition
real :: maxValue
do i = 1, n - 1
maxPosition = i
do j = i + 1, n
if ( arrayBase(maxPosition) < arrayBase(j) ) then
maxPosition = j
end if
end do
if ( i /= maxPosition ) then
maxValue = arrayBase(maxPosition)
arrayBase(maxPosition) = arrayBase(i)
arrayBase(i) = maxValue
maxValue = arrayEntourage(maxPosition)
arrayEntourage(maxPosition) = arrayEntourage(i)
arrayEntourage(i) = maxValue
end if
end do
end subroutine ArraySort
! 习题7-21 函数的最大值和最小值测试驱动程序
subroutine Exercises7_21
implicit none
real :: xStart, xEnd, xInc, minPosition, maxPosition, minValue, maxValue
real, external :: Exercises7_21_fun
call SearchFunctionExtermeValue(-1., 3., 200, Exercises7_21_fun, minPosition, minValue, maxPosition, maxValue)
write(*,1) 'Exercises7_21_fun 在 x = ', maxPosition, ' 处取到最大值 ',&
& maxValue, ',在 x = ', minPosition, ' 处取到最小值 ', minValue
1 format(1X, A, F5.2, A, F5.2, A, F5.2, A, F5.2)
end subroutine Exercises7_21
! 习题7-21 求取函数的最大值和最小值
subroutine SearchFunctionExtermeValue(firstValue, lastValue, numSteps, func, xmin, minValue, xmax, maxValue)
implicit none
real, intent(in) :: firstValue, lastValue
real, intent(out) :: xmin, xmax, minValue, maxValue
integer, intent(in) :: numSteps
real :: xInc
real, external :: func
real :: value, temp
value = firstValue
xmin = value
xmax = value
temp = func(value)
minValue = temp
maxValue = temp
do
value = value + (lastValue-firstValue)/numSteps
if ( value > lastValue ) exit
temp = func(value)
if ( temp > maxValue ) then
xmax = value
else if ( temp < minValue ) then
xmin = value
end if
end do
maxValue = func(xmax)
minValue = func(xmin)
end subroutine SearchFunctionExtermeValue
! 习题7-22 自定义函数给7-21
real function Exercises7_21_fun(x)
implicit none
real :: x
Exercises7_21_fun = x**3-5*x**2+5*x+2
end function Exercises7_21_fun
! 习题7-23 微分函数测试驱动程序 + 习题7-24 噪声值微分
! 程序结构:
! x = 0
! dx = 0.05
! 输入向量 = (sin(0+i*dx), i = 0,99)
! 调用子程序, 输入: 输入向量(100) 个数 dx 输出向量(99)
! 验证向量 = (cos(0+i*dx), i = 0,98)
! write 计算结果于实际值的接近程度判断结果为: abs(输出向量-验证向量) <= 临界值
! 子程序(输入向量(向量长度), 向量长度, 步长, 输出向量(向量长度-1))
! if abs(步长) <= 临界值 then
! write error!
! exit
! else
! 输出向量(i) = ((输入向量(i+1)-输入向量(i))/步长, i = 1, 99)
! end if
subroutine Exercises7_23
use MouName
implicit none
integer, parameter :: numSteps = 100
real, dimension(numSteps) :: arrayInput
real, dimension(numSteps-1) :: arrayResult, arrayCheck
real, dimension(numSteps-1) :: arrayNoise
integer :: i
real :: stepsLength
stepsLength = 0.05
arrayInput = [(sin(0+i*stepsLength), i = 0, numSteps-1)]
call Differential(arrayInput, numSteps, stepsLength, arrayResult)
arrayCheck = [(cos(0+i*stepsLength), i = 0, numSteps-2)]
write(*,*) '计算结果符合程度判断:', all((abs(arrayCheck-arrayResult) <= 0.05) .eqv. .TRUE.)
call RandomArrayCreator(numSteps-1, arrayNoise)
! arrayResult = arrayResult + arrayNoise * 0.04 - 0.02
write(*,'(10F6.2)') arrayResult - arrayCheck
end subroutine Exercises7_23
! 习题7-23 微分计算子程序
subroutine Differential(arrayInput, numSteps, stepsLength, arrayOutput)
use MouName
integer, intent(in) :: numSteps
real, dimension(numSteps), intent(in) :: arrayInput
real, dimension(numSteps-1), intent(out) :: arrayOutput
real, intent(in) :: stepsLength
if ( abs(stepsLength) <= criticalZero ) then
stop '步长过小, 请检查后再编译执行'
else
arrayOutput = [((arrayInput(i+1)-arrayInput(i))/stepsLength, i = 1, numSteps-1)]
end if
end subroutine Differential
! 噪声值产生(产生指定数目0~1的随机数)
subroutine RandomArrayCreator(randomNum, arrayOutput)
implicit none
real :: randomSeed = 207333
integer, intent(in) :: randomNum
real, dimension(randomNum), intent(out) :: arrayOutput
integer :: i
call seed0(randomSeed)
! arrayOutput = (/(call random(randomValue), i = 1, randomNum)/) ! call不返回值!
do i = 1, randomNum
call random(arrayOutput(i))
end do
end subroutine RandomArrayCreator
! 习题7-25 二进制补运算测试驱动程序
subroutine Exercises7_25
use MouName
implicit none
integer, parameter :: strLength = 8
character(len=strLength) :: str1, str2, strResult
integer :: intAdd, intSub
str1 = '11111111'
str2 = '00000001'
! strResult = BinaryAddition(str1, str2, strLength)
intAdd = BaseConversion_2To10(BinaryAddition(str1, str2, strLength), strLength)
intSub = BaseConversion_2To10(BinarySubtraction(str1, str2, strLength), strLength)
write(*,*) str1, ' + ', str2, ' 的结果为 ', BaseConversion_10To2(intAdd, strLength)
write(*,*) str1, ' - ', str2, ' 的结果为 ', BaseConversion_10To2(intSub, strLength)
write(*,*) BaseConversion_2To10(str1, strLength), ' + ', BaseConversion_2To10(str2, strLength), ' 的结果为 ', intAdd
write(*,*) BaseConversion_2To10(str1, strLength), ' - ', BaseConversion_2To10(str2, strLength), ' 的结果为 ', intSub
end subroutine Exercises7_25
! 习题7-26 线性最小二乘拟合 习题7-27 最小二乘拟合的相关系数 测试驱动程序
subroutine Exercises7_26
implicit none
integer, parameter :: arrayLength=20
real, dimension(arrayLength) :: arrayX, arrayY
real :: m, b, r
arrayX = (/-4.91, -3.84, -2.41, -2.62, -3.78, -0.52, -1.83, -2.01, +0.28, +1.08&
&, -0.94, +0.59, +0.69, +3.04, +1.01, +3.60, +4.53, +5.12, +4.43, +4.12/)
arrayY = (/-8.18, -7.49, -7.11, -6.15, -5.62, -3.30, -2.05, -2.83, -1.16, +0.52&
&, +0.21, +1.73, +3.96, +4.26, +5.75, +6.67, +7.70, +7.31, +9.05, 10.95/)
call LeastSquaresMethod(arrayX, arrayY, arrayLength, m, b, r)
write(*,1) m, b, r
1 format(1X, '计算得到的拟合方程为: y = ', F5.2, ' * x + ', F5.2, ' , 相关系数r为: ', F5.3)
end subroutine Exercises7_26
! 习题7-26 最小二乘法计算各参数(斜率、截距、相关系数)
subroutine LeastSquaresMethod(arrayX, arrayY, arrayLength, slope, intercept, correlationCoefficient)
implicit none
integer, intent(in) :: arrayLength ! 设定数组长度
real, dimension(arrayLength),intent(in) :: arrayX, arrayY ! 设定输入X、Y坐标数组
real, intent(out) :: slope, intercept, correlationCoefficient ! 设定输出斜率、截距和相关系数
integer :: i ! 循环变量
real :: x_bar, y_bar ! xy均值
real :: r ! 相关系数
real :: x_sum, y_sum ! xy总和
real :: x2_sum, xy_sum, y2_sum ! 各种参数
! 变量初始化
x_sum = 0
y_sum = 0
x2_sum = 0
y2_sum = 0
xy_sum = 0
i = 0
do i = 1, arrayLength ! 循环计算各参数
x_sum = x_sum + arrayX(i) ! x总和
y_sum = y_sum + arrayY(i) ! y总和
x2_sum = x2_sum + arrayX(i)**2 ! x方总和
y2_sum = y2_sum + arrayY(i)**2 ! y方总和
xy_sum = xy_sum + arrayX(i)*arrayY(i) ! xy总和
end do
x_bar = x_sum/real(i) ! x均值
y_bar = y_sum/real(i) ! y均值
slope = ( xy_sum - x_sum*y_bar )/( x2_sum - x_sum*x_bar ) ! 斜率
intercept = y_bar - slope*x_bar ! 截距
correlationCoefficient = ( real(i)*xy_sum - x_sum*y_sum )/& ! 相关系数
&sqrt( (real(i)*x2_sum - x_sum**2 )*( real(i)*y2_sum - y_sum**2 ) )
end subroutine LeastSquaresMethod
! 习题7-28 生日问题
subroutine Exercises7_28
implicit none
integer :: numPerson ! 房间内人数
real :: CompletelyDifferentProbability ! 调用理论值计算函数
real :: DifferentProbabilityTest ! 测试概率值计算
do numPerson = 2, 40
write(*,*) numPerson, '个人生日不同的理论概率为', CompletelyDifferentProbability(numPerson, 365)
write(*,*) numPerson, '个人生日不同的测试概率为', DifferentProbabilityTest(numPerson, 365)
end do
end subroutine Exercises7_28
! n个特定范围内的整数, 彼此之间完全不同的概率
real function CompletelyDifferentProbability(num, total)
implicit none
integer, intent(in) :: num ! 样本个数
integer, intent(in) :: total ! 可能的样本值总数
integer :: i ! 循环参数
CompletelyDifferentProbability = 1. ! 初始化输出
do i = 1, num - 1
CompletelyDifferentProbability = CompletelyDifferentProbability * real(total - i) / real(total)
end do
end function CompletelyDifferentProbability
! 从随机数中求n个特定范围内的整数, 彼此之间完全不同的概率
real function DifferentProbabilityTest(num, total)
implicit none
integer, intent(in) :: num ! 样本个数
integer, intent(in) :: total ! 样本值可能情况总数
integer, dimension(num) :: arrayTemp ! 样本值临时数组
integer, parameter :: numTest=90000 ! 测试次数
real :: randomValue
integer :: i, j ! 循环参数
integer :: temp ! 用于保存生成的随机数的临时值
call seed0(111111.) ! 获取初始随机参数
DifferentProbabilityTest = real(numTest) ! 初始化输出为测试次数
do i = 1, numTest ! 测试循环开始
arrayTemp = -1 ! 初始化随机数组
check: do j = 1, num ! 检查是否存在相同值循环
call random(randomValue) ! 获取一个1~0随机数
temp = floor(randomValue*total) ! 将随机数转化为1~总数之间的整数值
if ( any(arrayTemp==temp) ) then ! 如果存在相同数字
DifferentProbabilityTest = DifferentProbabilityTest - 1.! 中间值--
exit check ! 退出给随机数组赋值
end if ! 如果结束
arrayTemp(j) = temp ! 给随机数组当前位赋值
end do check ! 该次测试结束
end do ! 所有测试结束
DifferentProbabilityTest = DifferentProbabilityTest/real(numTest) ! 生成输出值(概率)
end function DifferentProbabilityTest
! 习题7-29 经时计算 习题公共模块
module ModuleExercises7_29 ! 定义模块
implicit none ! 声明显示表达
! 数据字典
integer, dimension(8) :: timeNow ! 当前时间数组
integer, dimension(8) :: timeOld ! 上一个时间数组
contains ! 所包含函数和子程序
! 习题7-29 经时计算 子程序1
subroutine set_timer ! 创建子程序1
implicit none ! 声明显示表达
call DATE_AND_TIME(values=timeNow) ! 调用当前时间子程序
end subroutine set_timer ! 结束子程序1
! 习题7-29 经时计算 子程序2
subroutine elapsed_time(timePast) ! 创建子程序2
implicit none ! 声明显示表达
real, intent(out) :: timePast ! 定义输出变量
timeOld = timeNow ! 传递值
call set_timer ! 调用子程序1
timePast = ((real(timeNow(3)-timeOld(3))*24 + real(timeNow(5)-timeOld(5)))&
&*60 + real(timeNow(6)-timeOld(6)))*60 + real(timeNow(7)-timeOld(7)) + &
&real(timeNow(8)-timeOld(8))/1000 ! 计算经历时间(秒)
end subroutine elapsed_time ! 结束子程序2
end module ModuleExercises7_29 ! 结束模块
! 习题7-29 经时计算 测试驱动程序 习题7-30 子程序计算
subroutine Exercises7_29 ! 定义测试驱动程序
use ModuleExercises7_29 ! 读取模块
implicit none ! 显式声明
integer, parameter :: arrayLength=100 ! 定义数组基础长度
real :: array1(arrayLength), array2(arrayLength*10), array3(arrayLength*100) ! 定义使用的随机数数组
real :: timePast ! 定义经历时间长度变量
real :: time1, time2, time3 ! 每次排序所消耗的时间
integer :: i, j ! 循环参数
! 变量初始化
time1 = 0
time2 = 0
time3 = 0
! 多次循环计算时间, 统计循环次数与用时总和
do j = 1, 10
call seed0(111111.) ! 随机数种子
do i = 1, 100 ! 给array1赋值
call random(array1(i))
end do
do i = 1, 1000 ! 给array2赋值
call random(array2(i))
end do
do i = 1, 10000 ! 给array3赋值
call random(array3(i))
end do
call set_timer ! 计算array1排序所需时间
call Sort(array1, arrayLength)
call elapsed_time(timePast)
time1 = time1 + timePast ! array1排序时间总计
call set_timer ! 计算array2排序所需时间
call Sort(array2, arrayLength*10)
call elapsed_time(timePast)
time2 = time2 + timePast ! array2排序时间总计
call set_timer ! 计算array3排序所需时间
call Sort(array3, arrayLength*100)
call elapsed_time(timePast)
time3 = time3 + timePast ! array3排序时间总计
end do
! 计算排序所需时间均值
time1 = time1/real(i)
time2 = time2/real(i)
time3 = time3/real(i)
write(*,1) time1, time2, time3 ! 打印排序时间信息
1 format(1X, '排序三个数组分别经历了', /&
&1X, '1. ', F10.8, ' s', /&
&1X, '2. ', F10.8, ' s', /&
&1X, '3. ', F10.8, ' s')
end subroutine Exercises7_29
! 习题7-30 排序子程序
subroutine Sort(array, n)
implicit none
integer :: n ! 数组长度
real, intent(inout), dimension(n) :: array ! 定义输入输出数组
integer :: i, j, maxPosition ! 循环参数和最大值位置
real :: maxValue ! 最大值的值
! 对数组进行排序
do i = 1, n - 1
maxPosition = i
do j = i + 1, n
if ( array(maxPosition) < array(j) ) then
maxPosition = j
end if
end do
if ( i /= maxPosition ) then
maxValue = array(maxPosition)
array(maxPosition) = array(i)
array(i) = maxValue
end if
end do
end subroutine Sort
! 习题7-31 估算无限序列 测试驱动程序
subroutine Exercises7_31
implicit none
integer, parameter :: arrayLength=8 ! 数组长度
real, dimension(arrayLength) :: arrayX, arrayY ! 输入数组X与输出数组Y
real :: ExEstimation ! 定义函数返回值类型
integer :: i ! 循环参数
arrayX = (/-10., -5., -1., 0., 1., 5., 10., 15./) ! 赋值输入数组X
! arrayY = (/((ExEstimation(arrayX(i)), i = 1, arrayLength))/) ! 好像不能这样用隐式循环
do i = 1, arrayLength ! 循环求输出数组Y的值
arrayY(i) = ExEstimation(arrayX(i)) ! 调用函数赋值
end do
write(*,1) arrayX, arrayY, exp(arrayX) ! 输出结果表格
1 format(1X, 'Form. e^x value estimation'/&
&1X, 'Input ', 8(1X, F9.2)/&
&1X, 'Output ', 8(1X, ES9.2)/&
&1X, 'Real ', 8(1X, ES9.2))
end subroutine Exercises7_31
! 习题7-31 EXP(X)
real function ExEstimation(x)
implicit none
real, intent(in) :: x ! 定义输入变量指数值
integer :: n ! 循环参数n
integer :: nFactorial ! n的阶乘
! 初始化变量
ExEstimation = 0
nFactorial = 1
do n = 0, 11 ! 取无限序列前12项
ExEstimation = ExEstimation + x**n/nFactorial ! 加和趋近结果值
nFactorial = nFactorial*(n+1) ! 计算下一次循环需要的阶乘值
end do
end function ExEstimation
! 习题7-32 使用子程序计算随机分布情况
subroutine Exercises7_32
implicit none
integer, parameter :: arrayLength=10000 ! 定义数组长为10000
real, dimension(arrayLength) :: array ! 定义随机数组
real :: Average, StandardDeviation ! 定义平均值和标准差为实型
integer :: i ! 循环参数
call seed0(111111.) ! 初始化随机数
do i = 1, arrayLength ! 循环给随机数组赋值
call random(array(i))
end do
! 输出结果
write(*,*) '随机数组平均值为: ', Average(array, arrayLength)
write(*,*) '随机数组标准差为: ', StandardDeviation(array, arrayLength)
write(*,*) '理论的平均值是0.5, 理论的标准偏差是', 1/sqrt(12.)
end subroutine Exercises7_32
! 习题7-33 计算数列平均值与标准偏差
real function Average(arrayInput, arrayLength)
implicit none
integer, intent(in) :: arrayLength ! 定义数组长度
real, dimension(arrayLength), intent(in) :: arrayInput ! 定义输入数组
integer :: i ! 循环参数
Average = 0 ! 初始化输出
do i = 1, arrayLength ! 循环加和数组值
Average = Average + arrayInput(i)
end do
Average = Average/real(i) ! 计算平均值
end function Average
real function StandardDeviation(arrayInput, arrayLength)
implicit none
integer, intent(in) :: arrayLength ! 定义数组长度
real, dimension(arrayLength), intent(in) :: arrayInput ! 定义输入数组
integer :: i ! 循环参数
real :: average ! 定义平均值
average = 0 ! 初始化平均值
StandardDeviation = 0 ! 初始化标准差
do i = 1, arrayLength ! 循环加和数组值
average = average + arrayInput(i)
end do
average = average/i ! 计算平均值
do i = 1, arrayLength ! 循环加和平均值与数组值的平方差
StandardDeviation = StandardDeviation + (average - arrayInput(i))**2
end do
StandardDeviation = sqrt(StandardDeviation/(i - 1)) ! 计算标准偏差
end function StandardDeviation
! 习题7-33 高斯(正态)分布
subroutine Exercises7_33
implicit none
integer, parameter :: arrayLength=1000 ! 定义数组长度
real, dimension(arrayLength) :: arrayNormal ! 定义随机正态分布数组
integer :: i ! 循环参数
real :: StandardDeviation, Average ! 定义函数返回值类型
call seed0(111111.) ! 初始化随机数
! do i = 1, int(arrayLength/2) ! 按照书上方法生成正态分布随机值
! call NormallyDistributedRandomValue(arrayNormal(2*i-1), arrayNormal(2*i))
! end do
do i = 1, arrayLength ! 使用BoxMuller变换得到正态分布随机值
call NormallyDistributedRandomValue1(arrayNormal(i))
end do
! write(*,'(25(F5.2, 1X))') arrayNormal ! 显示计算得到的正态分布数据
write(*,*) '标准的正态分布标准偏差为1.0, 而计算得到的随机数列标准偏差为',&
& StandardDeviation(arrayNormal, arrayLength), '平均值为',&
& Average(arrayNormal, arrayLength) ! 显示数据集的标准偏差与平均值
end subroutine
! 习题7-33 高斯分布(书上方法)
subroutine NormallyDistributedRandomValue(outputValue1, outputValue2)
implicit none
real, intent(out) :: outputValue1, outputValue2 ! 定义输出数据
real :: r ! 定义r值
do ! 循环获取x1,x2并判断
call random(outputValue1)
call random(outputValue2)
if ( outputValue1**2 + outputValue2**2 - 1. <= 0 ) exit ! 如果平方和小于1, 那么结束循环
end do
r = outputValue1**2 + outputValue2**2 ! 计算平方和
! write(*,*) r
outputValue1 = sqrt(-2.*log(r)/r)*outputValue1 ! 计算y1(输出值1)
outputValue2 = sqrt(-2.*log(r)/r)*outputValue2 ! 计算y2(输出值2)
end subroutine NormallyDistributedRandomValue
! 习题7-33 高斯分布(BoxMuller变换)
subroutine NormallyDistributedRandomValue1(outputValue)
implicit none
real, parameter :: PI = 3.14159265 ! 定义常数PI
real, intent(out) :: outputValue ! 定义输出值(符合正态分布的)
real :: outputValue1 ! 另一个需要的变量,但是不输出
call random(outputValue1) ! 获取均匀分布的随机数第一个数值
call random(outputValue) ! 获取均匀分布的随机数第二个数值
outputValue = sqrt(-2.*log(outputValue1))*cos(2*PI*outputValue) ! BoxMuller变换, 并输出结果
end subroutine NormallyDistributedRandomValue1
! 习题7-34 引力
subroutine Exercises7_34
implicit none
real, parameter :: mEarth=5.98E24 ! 地球质量(kg)
real :: m ! 卫星质量(kg)
real :: r ! 地心与卫星距离(m)
real :: Gravity ! 定义函数返回类型为实型
m = 1000. ! 设定卫星质量(kg)
r = 38000.*1000. ! 设定地卫距离(m)
write(*,*) '地球与卫星之间的引力大小为', Gravity(m, mEarth, r), ' N'
end subroutine Exercises7_34
! 引力计算
real function Gravity(m1, m2, r)
implicit none
real, parameter :: G=6.672E-11 ! 万有引力常数
real, intent(in) :: m1, m2, r ! 输入实型质量1,质量2,间距
Gravity = G*m1*m2/r**2 ! 输出两物体间引力值
end function Gravity
! 习题7-35 堆排序
!

517
第8章习题.f90 Normal file
View File

@ -0,0 +1,517 @@
! ==============================================================================
! 通过 gfortran ./test.f90 -o ./run && ./run 运行
! 程序名:
! 习题
! 目的:
! 练习用
! 修订记录:
! 日期 编程者 改动描述
! =================== ============= =====================================
! 2021-04-26 16:53:03 Sola 测验8-1 7 测试数组调用
! 2021-04-30 18:03:39 Sola 习题8-7 输出数组中正负数和0的个数
! 2021-04-30 18:49:30 Sola 习题8-8 可分配数组输入数据定义并计算行列和
! 2021-04-30 19:26:59 Sola 习题8-10 没看懂啥意思, 跳过
! 2021-04-30 19:27:16 Sola 习题8-11 在赋值中修改数组范围,太长了,跳过
! 2021-04-30 19:30:55 Sola 习题8-12 DO循环和WHERE结构比较
! 2021-04-30 20:10:23 Sola 习题8-13 计算年平均温度
! 2021-04-30 20:46:31 Sola 习题8-14 矩阵乘法 8-15 8-16
! 2021-05-01 00:32:18 Sola 习题8-17 相对极大(鞍点)
! 2021-05-01 02:01:58 Sola 习题8-18 金属盘温度分布
! 程序结构:
!
! ==============================================================================
! 模块:
module Module_8
implicit none
! 数据字典
! 声明常数
REAL, PARAMETER :: PI=3.14159265 ! PI值
REAL, PARAMETER :: e=2.718281828459 ! 自然对数
INTEGER, PARAMETER :: arrayLength=20 ! 数组基准长度
! 声明变量
! 创建显式接口
contains
! subroutine SubName(varName1,varName2)
! implicit none
! ! 数据字典
! end subroutine SubName
end module Module_8
! ==============================================================================
! 主程序:
program ProName
implicit none
! call Exercises8_1_7
! call Exercises8_7
! call Exercises8_8
! call Exercises8_9
! call Exercises8_10
! call Exercises8_11
! call Exercises8_12
! call Exercises8_13
! call Exercises8_14
! call Exercises8_17
call Exercises8_18
! 数据字典
! 声明常量
! 声明变量
! 变量初始化
! 数据输入
! 运算过程
! 结果输出
end program ProName
! ==============================================================================
! 子程序
! subroutine SubName(varName1,varName2)
! use MouName
! implicit none
! Type, intent(inout) :: varName
! end subroutine SubName
! ==============================================================================
! 函数
! function FunName(varName1,varName2)
! use MouName
! implicit none
! end function FunName
! ==============================================================================
! 测试8-1.7 使用数组从数组中调取元素
subroutine Exercises8_1_7
implicit none
integer, dimension(4) :: list1=(/1,4,2,2/) ! 定义数组1
integer, dimension(3) :: list2=(/1,2,3/) ! 定义数组2
integer, dimension(5, 5) :: array ! 定义数组3
integer :: i, j ! 循环参数
do i = 1, 5
do j = 1, 5
array(i, j) = i + 10*j ! 数组3赋值
end do
end do
write (*,'(1X, 4I4)') array(list1, list2) ! 测试通过数组调用数组
end subroutine Exercises8_1_7
! 习题8-7 统计数组中正负数和0的个数
subroutine Exercises8_7
implicit none
real, dimension(-50:50, 0:100) :: values ! 定义随机数组
integer :: i, j ! 循环参数
integer :: numPositive, numNegative, numZero ! 统计参数
! 初始化变量
numPositive = 0
numNegative = 0
numZero = 0
! FORALL方式随机赋值(好像不能这么用, 所以注释)
! forall (i=-50:50, j=0:100)
! call random_seed()
! call random_number(values(i, j))
! end forall
! 嵌套循环赋值
do i = -50, 50
do j = 0, 100
call random_seed() ! 根据日期, 时间获取随机数种子
call random_number(values(i, j)) ! 调用随机数子程序给数组赋值
end do
end do
values = values * 200. - 100. ! 调整数组范围
! 循环计算正负数和0的个数
do i = -50, 50
do j = 0, 100
if (values(i, j) > 0) then
numPositive = numPositive + 1
elseif (values(i, j) < 0) then
numNegative = numNegative + 1
else
numZero = numZero + 1
end if
end do
end do
! 输出结果
write(*,1) ' 测试组', numPositive, numNegative, numZero
write(*,1) ' 对照组', count(values > 0.), count(values < 0.), count(values == 0.)
1 format(1X, A/&
&1X, '数组中有正数 ', I5, '个'/&
&1X, '数组中有负数 ', I5, '个'/&
&1X, '数组中有0 ', I5, '个')
end subroutine Exercises8_7
! 习题8-8 可分配数组输入数据定义并计算行列和, 注意IO操作的返回值参数和数组分配不同
subroutine Exercises8_8
implicit none
real, dimension(:, :), allocatable :: array ! 定义可分配数组
integer :: errorLevel ! 错误码
integer :: a, b ! 数组范围
integer :: i ! 循环参数
character(len=20) :: inforError ! 错误信息
! 打开一个临时文件
open(unit=1, status='scratch', iostat=errorLevel, iomsg=inforError)
if (errorLevel /= 0) stop inforError ! 检测打开文件是否成功
! 输入参数 8-8
! write(1, *) 2, 4
! write(1, *) -24., -1121., 812.1, 11.1
! write(1, *) 35.6, 8.1E3, 135.23, -17.3
! 输入参数 8-9
write(1, *) 4, 5
write(1, *) 33., -12., 16., 0.5, -1.9
write(1, *) -6., -14., 3.5, 11., 2.1
write(1, *) 4.4, 1.1, -7.1, 9.3, -16.1
write(1, *) 0.3, 6.2, -9.9, -12., 6.8
! write(1, *) , , , ,
rewind(unit=1) ! 回到文件开头
read(1,*) a, b ! 读取数组范围
! 检查数组范围
if (a > 100) a = 100
if (b > 100) b = 100
allocate(array(a, b), stat=errorLevel, errmsg=inforError) ! 分配数组
if (errorLevel /= 0) stop inforError ! 检测数组分配是否成功
do i = 1, a
read(1, *) array(i, :) ! 数组赋值
end do
! 输出统计结果
1 format(1X, 'Sum of ', A, ' ', I3, ' = ', F10.3)
do i = 1, a
write(*, 1) 'row', i, sum(array(i, :))
end do
do i = 1, b
write(*, 1) 'col', i, sum(array(:, i))
end do
if (allocated(array)) deallocate(array, stat=errorLevel)
if (errorLevel /= 0) print *, "array: Deallocation request denied"
close(unit=1)
end subroutine Exercises8_8
! 习题8-10 没看懂啥意思, 跳过
! 习题8-11 在赋值中修改数组范围,太长了,跳过, 写了个简化版的利用F03的特性实现
! 不过有一点需要注意好像不可以用allocate语句多次定义有点理解无缝是什么意思了
subroutine Exercises8_11
implicit none
real, dimension(:), allocatable :: array ! 定义可分配数组
integer :: i ! 循环变量
integer :: errorLevel ! 错误码
character(len=20) :: inforError ! 错误信息
real :: temp ! 临时变量
allocate(array(1), stat=errorLevel, errmsg=inforError) ! 分配数组
if (errorLevel /= 0) stop inforError ! 检测数组分配状态
call random_seed() ! 根据日期时间产生随机数种子
call random_number(array(1)) ! 用随机数给数组赋值
do i = 2, 50 ! 循环产生随机数, 并给数组赋值
call random_seed()
call random_number(temp)
array = (/array, temp/) ! 利用F03特性扩展数组
end do
write(*,'(1X, 10F6.3, " ")') array ! 10个一行输出数组内容
if (allocated(array)) deallocate(array, stat=errorLevel)
if (errorLevel /= 0) print *, "array: Deallocation request denied"
end subroutine Exercises8_11
! 习题8-12 DO循环和WHERE结构比较
subroutine Exercises8_12
implicit none
integer, parameter :: arrayLength=10 ! 设置数组基本长度
real, dimension(100*arrayLength, arrayLength, 3*arrayLength) :: arr, arrayTemp ! 定义数组
integer :: i, j, k ! 循环参数
! Where结构中也不可调用子程序
! real :: temp
! arr = 0.
! where(arr == 0.)
! call random_seed()
! call random_number(temp)
! arr = temp
! end where
do i = 1, 100*arrayLength
do j = 1, arrayLength
do k = 1, 3*arrayLength
call random_seed()
call random_number(arr(i, j, k)) ! 对数组进行循环赋值
end do
end do
end do
arr = arr*1300 ! 调整数组范围
arrayTemp = arr ! 拷贝数组
write(*, *) 'Do循环判断开始, 数组总和为', sum(arr) ! 参照
do i = 1, 100*arrayLength
do j = 1, arrayLength
do k = 1, 3*arrayLength
if (arr(i, j, k) > 1000.) arr(i, j, k) = 1000. ! DO判断
end do
end do
end do
write(*, *) 'Do循环判断结束, 数组总和为', sum(arr) ! 输出结果
write(*, *) 'Where结构开始' ! 参照
where(arrayTemp > 1000.)
arrayTemp = 1000. ! WHERE判断, Where结构真的方便...
end where
write(*, *) 'Where结构结束, 数组总和为', sum(arrayTemp) ! 输出结果
end subroutine Exercises8_12
! 习题8-13 计算年平均温度
subroutine Exercises8_13
implicit none
real, dimension(6, 6) :: array ! 定义数组
integer :: i ! 循环参数
integer :: errorLevel ! 错误码
character(len=20) :: inforError ! 错误信息
open(unit=1, status='scratch', iostat=errorLevel, iomsg=inforError) ! 打开临时文件
if (errorLevel /= 0) stop inforError ! 判断打开成功与否
write(1, 1) 68.2, 72.1, 72.5, 74.1, 74.4, 74.2, & ! 输入统计数据
&69.4, 71.1, 71.1, 71.9, 73.1, 73.6, &
&68.9, 70.5, 70.9, 71.5, 72.8, 73.0, &
&68.6, 69.9, 70.4, 70.8, 71.5, 72.2, &
&68.1, 69.3, 69.8, 70.2, 70.9, 71.2, &
&68.3, 68.8, 69.6, 70.0, 70.5, 70.9
1 format(6F5.1) ! 设定统计数据输入格式
rewind(unit=1) ! 回到文件开头
read(1,*) (array(i, :), i = 1, 6) ! 给数组赋值
2 format(1X, F4.1, A8, ' 的平均气温为 ', F4.1, ' ℃') ! 设定结果输出格式
do i = 1, 6
write(*, 2) 29.5 + real(i)*0.5, '°N lat ', sum(array(i, :))/6. ! 输出纬度平均气温
end do
do i = 1, 6
write(*, 2) 89.5 + real(i)*0.5, '°W long', sum(array(:, i))/6. ! 输出经度平均气温
end do
write(*, 3) '所有统计地点年平均温度为 ', sum(array)/36., ' ℃' ! 输出所有地区平均气温
3 format(1X, A, F4.1, A) ! 设定结果输出格式
close(unit=1) ! 关闭文件, 此句可忽略
end subroutine Exercises8_13
! 习题8-14 矩阵乘法, 注意, F03虽然可以自动分配大小, 但是还是得先给他分配一个大小
subroutine Exercises8_14
implicit none
! real, dimension(:,:), allocatable :: MatrixMultplication
real, dimension(:, :), allocatable :: array1, array2, array3
integer :: i, j, k
integer :: a, b
integer :: errorLevel ! 错误码
character(len=20) :: inforError ! 错误信息
open(unit=1, status='scratch', iostat=errorLevel, iomsg=inforError) ! 打开临时文件
if (errorLevel /= 0) stop inforError ! 判断打开成功与否
open(unit=2, status='scratch', iostat=errorLevel, iomsg=inforError) ! 打开临时文件
if (errorLevel /= 0) stop inforError ! 判断打开成功与否
! 习题8-14使用
! 匹配的, 输入矩阵1
! write (1, '(A)') " 2, 2",&
! &" 3.0, -1.0",&
! &" 1.0, 2.0"
! ! 不匹配的, 输入矩阵1
! ! write (1, '(A)') " 2, 2, 3",&
! ! &" 3.0, -1.0, 1.0",&
! ! &" 1.0, 2.0, 1.0"
! ! 输入矩阵2
! write (2, '(A)') " 2, 2",&
! &" 1.0, 4.0",&
! &" 2.0, -3.0"
! 习题8-15使用
write (1, '(A)') " 2, 4",&
&" 1.0, -5.0, 4.0, 2.0",&
&" -6.0, -4.0, 2.0, 2.0"
write (2, '(A)') " 4, 3",&
&" 1.0, -2.0, -1.0",&
&" 2.0, 3.0, 4.0",&
&" 0.0, -1.0, 2.0",&
&" 0.0, -3.0, 1.0"
rewind(unit=1) ! 回到文件1第一行
rewind(unit=2) ! 回到文件2第一行
read(1, *) a, b ! 读取矩阵1大小
allocate(array1(a, b), stat=errorLevel) ! 分配矩阵1
if (errorLevel /= 0) print *, "array1: Allocation request denied"
read(1, *) (array1(i, :), i = 1, a) ! 给矩阵1赋值
read(2, *) a, b ! 读取矩阵2大小
allocate(array2(a, b), stat=errorLevel) ! 分配矩阵2
if (errorLevel /= 0) print *, "array2: Allocation request denied"
read(2, *) (array2(i, :), i = 1, a) ! 给矩阵2赋值
! 关闭打开的临时文件(实际上一般可以不管)
close(unit=1)
close(unit=2)
if (size(array1, 2) /= size(array2, 1)) stop "警告! 数组维度不匹配!"! 检测是否可进行矩阵乘法
allocate(array3(size(array1, 1), size(array2, 2)), stat=errorLevel) ! 分配矩阵3
if (errorLevel /= 0) print *, "array3: Allocation request denied"
! array3 = MatrixMultplication(array1, array2)
array3 = 0. ! 初始化矩阵3
! 习题8-14, 8-15使用
! FORALL结构给矩阵3赋值, 注意这里会警告重复计算, 别管他, 设计就是这样
! forall(i = 1:size(array1, 1), j = 1:size(array1, 2), k = 1:size(array2, 2))
! array3(i, k) = array1(i, j)*array2(j, k) + array3(i, k)
! end forall
! 习题8-16 使用(改写后的)
array3 = matmul(array1, array2)
! 关闭数组, 释放资源
if (allocated(array2)) deallocate(array2, stat=errorLevel)
if (errorLevel /= 0) print *, "array2: Deallocation request denied"
if (allocated(array1)) deallocate(array1, stat=errorLevel)
if (errorLevel /= 0) print *, "array1: Deallocation request denied"
write(*, 2) (array3(i, :), i = 1, size(array3, 1)) ! 输出矩阵乘法计算结果
2 format(2(1X, F7.2, 1X))
if (allocated(array3)) deallocate(array3, stat=errorLevel)
if (errorLevel /= 0) print *, "array3: Deallocation request denied"
! contains
! function MatrixMultplication(arrayInput1, arrayInput2)
! implicit none
! real, dimension(:,:), allocatable, intent(in) :: arrayInput1, arrayInput2
! real, dimension(:,:), allocatable :: MatrixMultplication
! integer :: i, j, k
! if (size(arrayInput1, 2) /= size(arrayInput2, 1)) stop "警告! 数组维度不匹配!"
! MatrixMultplication = 0.
! forall(i = 1:size(arrayInput1, 1), j = 1:size(arrayInput1, 2), k = 1:size(arrayInput2, 2))
! MatrixMultplication(i, k) = arrayInput1(i, j)*arrayInput2(j, k) + MatrixMultplication(i, k)
! end forall
! end function MatrixMultplication
end subroutine Exercises8_14
! 习题8-17 相对极大(鞍点)
! 根据鞍点的定义, 可以直接遍历程序中每个点,,, 不过这样好像效率不太高的样子
! 1. 鞍点比上一行的值都大, 比下一行的值都大, 比左一列的值都大, 比右一列的值都大
! 2. 检测筛选之后的值
! 所以, 需要有一个输入矩阵, 有一个标定矩阵, 确定其位置的, i, j, 以及坐标数组(可扩展)
subroutine Exercises8_17
implicit none
real, dimension(:, :), allocatable :: arrayInput ! 输入矩阵
logical, dimension(:, :), allocatable :: arrayCheck ! 检测矩阵
integer :: i, j ! 循环参数
integer, dimension(:, :), allocatable :: arrayPoint ! 鞍点坐标
integer :: sizeX, sizeY ! 矩阵大小
integer :: errorLevel ! 错误码
integer :: num ! 鞍点个数
character(len=20) :: inforError ! 错误信息
! 变量初始化
num = 0
open(unit=1, status='scratch', iostat=errorLevel, iomsg=inforError) ! 打开临时文件
if (errorLevel /= 0) stop inforError ! 确认临时文件成功打开
write (1, '(A)') " 8, 8",& ! 向临时文件写入矩阵
&" 2.0, -1.0, -2.0, 1.0, 3.0, -5.0, 2.0, 1.0",&
&" -2.0, 0.0, -2.5, 5.0, -2.0, 2.0, 1.0, 0.0",&
&" -3.0, -3.0, -3.0, 3.0, 0.0, 0.0, -1.0, -2.0",&
&" -4.5, -4.0, -7.0, 6.0, 1.0, -3.0, 0.0, 5.0",&
&" -3.5, -3.0, -5.0, 0.0, 4.0, 17.0, 11.0, 5.0",&
&" -9.0, -6.0, -5.0, -3.0, 1.0, 2.0, 0.0, 0.5",&
&" -7.0, -4.0, -5.0, -3.0, 2.0, 4.0, 3.0, -1.0",&
&" -6.0, -5.0, -5.0, -2.0, 0.0, 1.0, 2.0, 5.0"
rewind(unit=1) ! 返回初始行
read(1, *) sizeY, sizeX ! 获得矩阵大小
allocate(arrayInput(sizeX, sizeY), stat=errorLevel) ! 定义输入矩阵
if (errorLevel /= 0) print *, "arrayInput: Allocation request denied"
allocate(arrayCheck(sizeX, sizeY), stat=errorLevel) ! 定义检测矩阵
if (errorLevel /= 0) print *, "arrayCheck: Allocation request denied"
allocate(arrayPoint(2, 1), stat=errorLevel) ! 定义鞍点坐标数组
if (errorLevel /= 0) print *, "arrayPoint: Allocation request denied"
read(1, *) (arrayInput(i, :), i = 1, sizeY) ! 给输入矩阵赋值
close(unit=1, iostat=errorLevel, iomsg=inforError) ! 关闭临时文件
if (errorLevel /= 0) stop inforError ! 检测是否关闭成功
arrayCheck = .FALSE. ! 初始化检测矩阵
do i = 2, sizeX - 1 ! 标记行间最大值
arrayCheck(i, 2:sizeY-1) = (arrayInput(i, 2:sizeY-1) > arrayInput(i-1, 2:sizeY-1)) .and. &
&(arrayInput(i, 2:sizeY-1) > arrayInput(i+1, 2:sizeY-1))
end do
do j = 2, sizeY - 1 ! 标记行列间最大值
arrayCheck(2:sizeX-1, j) = (arrayInput(2:sizeX-1, j) > arrayInput(2:sizeX-1, j-1)) .and. &
&(arrayInput(2:sizeX-1, j) > arrayInput(2:sizeX-1, j+1)) .and. &
& arrayCheck(2:sizeX-1, j)
end do
forall (i=2:sizeX-1, j=2:sizeY-1, arrayCheck(i, j)) ! 标记点与左上比较并迭代
arrayCheck(i, j) = (arrayInput(i, j) > arrayInput(i-1, j-1))
end forall
forall (i=2:sizeX-1, j=2:sizeY-1, arrayCheck(i, j)) ! 标记点与左下比较并迭代
arrayCheck(i, j) = (arrayInput(i, j) > arrayInput(i+1, j-1))
end forall
forall (i=2:sizeX-1, j=2:sizeY-1, arrayCheck(i, j)) ! 标记点与右下比较并迭代
arrayCheck(i, j) = (arrayInput(i, j) > arrayInput(i+1, j+1))
end forall
forall (i=2:sizeX-1, j=2:sizeY-1, arrayCheck(i, j)) ! 标记点与右上得到鞍点
arrayCheck(i, j) = (arrayInput(i, j) > arrayInput(i-1, j+1))
end forall
if (allocated(arrayInput)) deallocate(arrayInput, stat=errorLevel) ! 关闭输入矩阵
if (errorLevel /= 0) print *, "arrayInput: Deallocation request denied"
do i = 2, sizeX - 1
do j = 2, sizeY - 1
if (arrayCheck(j, i) .eqv. .TRUE.) then
num = num + 1
arrayPoint(:, num) = (/i, j/) ! 遍历检测矩阵, 得到鞍点坐标
end if
end do
end do
if (allocated(arrayCheck)) deallocate(arrayCheck, stat=errorLevel) ! 关闭检测矩阵
if (errorLevel /= 0) print *, "arrayCheck: Deallocation request denied"
write(*, 1) '矩阵中的鞍点坐标如下:', (arrayPoint(:, i), i = 1, num) ! 输出结果
1 format(1X, A/&
&6('(', I2, ',', I2, ') ')) ! 定义输出格式
if (allocated(arrayPoint)) deallocate(arrayPoint, stat=errorLevel) ! 关闭坐标数组
if (errorLevel /= 0) print *, "arrayPoint: Deallocation request denied"
end subroutine Exercises8_17
! 习题8-18 金属盘温度分布, 总感觉这题好像有点难度(如果要优化算法的话, 直接穷举确实容易倒是, 就是浪费计算资源, 模仿自然温度扩散写个循环吧)
! 基本路线原则如下:
! 1. 计算前进方向一格周围的格子情况, 以确定下一次前进方向, 并累计前进次数
! 1.1 当前进次数为0时, 朝方向1前进1格, 前进次数+1,
! 1.2 当前进次数大于1时:
! 1.2.1 检测前进方向格子状态
! 1.2.1.1 如果为0(未计算), 前进一格, 并检测 优先侧方向 格子状态
! 1.2.1.1.1 如果为0(未计算), 则下次前进方向为 优先侧方向
! 1.2.1.1.2 如果为1(已计算)或-1(固定值), 检测 前进方向 格子状态
! 1.2.1.1.2.1 如果为0(未计算), 则下次前进方向为 当前方向
! 1.2.1.1.2.2 如果为1(已计算)或-1(固定值). 检测 非优先侧方向
! 1.2.1.1.2.2.1 如果为0(未计算), 则下次前进方向为 非优先侧方向
! 1.2.1.1.2.2.2 如果为1(已计算)或-1(固定值), 这时候无路可走, 检测所有格子状态
! 1.2.1.1.2.2.2.1 所有格子为1, 检测此次迭代计算结果
! 1.2.1.1.2.2.2.1.1 符合条件, 退出
! 1.2.1.1.2.2.2.1.1 不符合条件, 初始化检测状态, 进行下一次循环
! 1.2.1.1.2.2.2.2 存在格子不为1, 选定可选位置中
! 1.2.1.2 如果为1(已计算或固定值)
! 突然发现越来越复杂了, 舍弃这种思路
! 按照距离优先计算, 优先计算离热源近的方块, 但问题是这样只能适应单热源的部分, 无法计算多热源(说得好像之前那种就能计算多热源了)
! 为了处理多热源的问题, 引入时序步进的想法, 假定热量传递速度相同
! 这样就是多热源画同样的同心圆, 在此范围内未被计算过的方块会被标记为2
! 对标记为2的方块进行统计, 周围被标记为0的格子数为2的, 被标记为3
! 优先计算标记为2的方块, 再计算标记为3的方块
! 步进计算, 直到无方块被标记
! 从距离的角度, 选取欧式距离似乎最为合适, 选取曼哈顿距离则计算最为简单, 最终还是选取了欧式距离
! 有时候感觉自己就是个ZZ, 直接算出来每个点的距离, 然后排序计算不就好了, 干嘛费那么大劲还去考虑步进每次包括的点位和点位计算顺序
subroutine Exercises8_18
implicit none
real, dimension(10, 10) :: metalPlate, metalPlateOld ! 金属盘表面温度, 及对照组
integer, dimension(63, 2) :: pointList ! 优化后的计算顺序
integer :: i, j, k ! 循环参数(什么都干的那种)
real :: temp, distense ! 用于判断是否符合要求
! 初始化计算顺序用数组
metalPlate = 0.
metalPlate(2:9, 2:9) = 1.
metalPlate(3, 8) = 0.
! 计算需要计算温度处距离热源的距离
forall (i = 2: 9, j = 2: 9, metalPlate(i, j) == 1.)
metalPlate(i, j) = (i-3)**2 + (j-8)**2
end forall
i = 0
! 输出计算顺序
do
i = i + 1
pointList(i, :) = minloc(metalPlate, mask=metalPlate>0.)
metalPlate(pointList(i, 1), pointList(i, 2)) = 0.
if (all(metalPlate == 0.)) exit
end do
! 初始化金属盘表面温度
metalPlate = 20.
metalPlate(2:9, 2:9) = 50.
metalPlate(3, 8) = 100.
j = 0
! 开始迭代计算金属盘表面温度
do
distense = 0.
do i = 1, size(pointList, 1)
temp = metalPlate(pointList(i, 1), pointList(i, 2))
metalPlate(pointList(i, 1), pointList(i, 2)) = (metalPlate(pointList(i, 1)+1, pointList(i, 2)) + &
&metalPlate(pointList(i, 1), pointList(i, 2)+1) + metalPlate(pointList(i, 1)-1, pointList(i, 2)) &
&+ metalPlate(pointList(i, 1), pointList(i, 2)-1))/4.
if (abs(temp-metalPlate(pointList(i, 1), pointList(i, 2))) > distense)&
& distense = abs(temp-metalPlate(pointList(i, 1), pointList(i, 2)))
end do
if (distense < 0.01) exit
j = j + 1
end do
write(*, '(" 共经历", I3, "次迭代计算")') j
write(*, *) '节点(5, 5)处稳定状态下温度为', metalPlate(5, 5)
write(*, '(" ", 10F7.2)') (metalPlate(i, :), i = 1, 10)
! 初始化金属盘表明温度
metalPlate = 20.
metalPlate(2:9, 2:9) = 50.
metalPlate(3, 8) = 100.
k = 0
! 开始迭代计算金属盘表面温度
do
metalPlateOld = metalPlate
forall(i = 1:10, j = 1:10, metalPlate(i, j) /= 20. .and. metalPlate(i, j) /= 100.)
metalPlate(i, j) = (metalPlate(i+1, j) + metalPlate(i, j+1) + metalPlate(i-1, j) + metalPlate(i, j-1))/4.
end forall
k = k + 1
if (all(abs(metalPlate-metalPlateOld) < 0.01)) exit
end do
write(*, '(" 共经历", I3, "次迭代计算")') k
write(*, *) '节点(5, 5)处稳定状态下温度为', metalPlate(5, 5)
write(*, '(" ", 10F7.2)') (metalPlate(i, :), i = 1, 10)
end subroutine Exercises8_18

796
第9章习题.f90 Normal file
View File

@ -0,0 +1,796 @@
! ==============================================================================
! 通过 gfortran ./test.f90 -o ./run && ./run 运行
! 程序名:
! 第9章习题及书上例题
! 目的:
!
! 修订记录:
! 日期 编程者 改动描述
! =================== ============= =====================================
! 2021-05-06 18:56:24 Sola 例9-1 模仿正常的上三角解法
! 2021-05-07 00:20:30 Sola 例9-1 高斯-亚当消元法(书上解法确实好)
! 2021-05-07 17:48:03 Sola 习题9-4 判断程序正误
! 2021-05-07 18:00:54 Sola 习题9-5 判断输出结果,跳过
! 2021-05-07 19:17:23 Sola 习题9-6 矩阵乘法子程序, 显式结构
! 2021-05-07 19:17:53 Sola 习题9-7 矩阵乘法子程序, 显式接口不定结构
! 2021-05-07 19:20:11 Sola 习题9-8 用不定结构形参数组修改例9-1
! 2021-05-07 20:22:22 Sola 习题9-9 测试图9-6的子程序
! 2021-05-07 21:42:49 Sola 习题9-11 测试程序运行
! 2021-05-07 21:59:54 Sola 习题9-12 修改测试程序
! 2021-05-07 22:16:18 Sola 习题9-13 模拟掷色子
! 2021-05-08 13:02:55 Sola 习题9-14 创建逐元过程运算
! 2021-05-08 14:59:48 Sola 习题9-15 将9-14换成pure纯函数
! 2021-05-09 00:52:48 Sola 习题9-16 高阶最小二乘回归
! 2021-05-09 13:49:16 Sola 习题9-17 噪声值对拟合结果的影响
! 2021-05-09 14:36:52 Sola 习题9-18 任意高阶最小二乘回归9-16直接写了跳过
! 2021-05-09 14:38:55 Sola 习题9-19 4阶最小二乘回归噪声影响
! 2021-05-09 15:12:56 Sola 习题9-20 利用高阶最小二乘回归进行插值处理
! 2021-05-09 15:24:01 Sola 习题9-21 推理,推理范围外的值
! 程序结构:
!
! ==============================================================================
! 模块:
module Chapter9
implicit none
! 数据字典
! 声明常数
REAL, PARAMETER :: PI=3.14159265 ! PI值
REAL, PARAMETER :: e=2.718281828459 ! 自然对数
INTEGER, PARAMETER :: arrayLength=20 ! 数组基准长度
! Example 9-1
! real, dimension(:), allocatable :: arrayX
! read, dimension(:, :), allocatable :: N
integer :: m, n
! 声明变量
! 创建显式接口
contains
! subroutine SubName(varName1,varName2)
! implicit none
! ! 数据字典
! end subroutine SubName
! 上三角消元法
! subroutine UpperTriangleElimination(matrixInput, arrayX, m, n)
! implicit none
! integer, intent(in) :: m, n ! 矩阵大小与X解向量长度
! real, dimension(m, m+1), intent(inout) :: matrixInput ! 输入矩阵(输入)
! real, dimension(n), intent(inout) :: arrayX ! 解向量(输入输出)
! real, dimension(m+1) :: matrixTemp ! 临时向量, 用于矩阵行交换
! integer :: i ! 局部变量: 循环参数
! if ( m /= 1 ) then ! 如果矩阵行数不为1
! if ( abs(matrixInput(1, 1)) < 1.0E-30 ) then ! 如果矩阵首位为0
! do i = 2, m ! 从其余行选择不为0的交换
! if ( abs(matrixInput(i, 1)) >= 1.0E-30 ) then
! matrixTemp = matrixInput(i, :)
! matrixInput(i, :) = matrixInput(1, :)
! matrixInput(1, :) = matrixTemp
! exit
! end if
! end do
! end if
! matrixInput(1, :) = matrixInput(1, :)/matrixInput(1, 1) ! 单位化矩阵第一行
! do i = 2, m ! 消去其他行所有第一列的系数
! matrixInput(i, :) = matrixInput(i, :) - matrixInput(1, :)*matrixInput(i, 1)
! end do
! if ( all(matrixInput(2:m, 2) == 0) ) then ! 检查第二列第二行到最后一行不为0
! stop "输入矩阵不满秩,无法求解" ! 如果为0, 则输入矩阵不满秩, 无解
! else
! call GaussAdamElimination(matrixInput(2:m, 2:m+1), arrayX, m-1, n) ! 递归调用自身
! end if
! arrayX(n-m+1) = matrixInput(1, m+1) - matrixInput(1, 2:m)*arrayX(n-m+2:n) ! 计算当前位X值
! else
! arrayX(n) = matrixInput(1, m+1)/matrixInput(1, 1) ! 如果矩阵行数为1, 直接计算当前位X值
! end if
! end subroutine UpperTriangleElimination
! 高斯亚当消元法 会破坏输入数组
subroutine GaussAdamElimination(matrixInput, m, arrayX, maxLimit, error)
implicit none
integer, intent(in) :: m ! 输入的方程组数量
integer, intent(in) :: maxLimit ! 矩阵大小与X解向量长度
real, dimension(maxLimit, maxLimit), intent(inout) :: matrixInput ! 输入矩阵(输入)
real, dimension(maxLimit), intent(inout) :: arrayX ! 输入常数向量, 输出X解向量
integer, intent(out) :: error ! 错误值
real :: temp ! 临时值, 用于数值交换
integer :: maxLocate ! 最大值所在行
integer :: i, n ! 局部变量: 循环参数
do n = 1, m
maxLocate = n ! 初始化绝对值最大的位置
do i = n+1, m ! 执行最大支点技术,减少舍入误差
if ( abs(matrixInput(i, n)) > abs(matrixInput(maxLocate, n)) ) then
maxLocate = i
end if
end do
if ( abs(matrixInput(maxLocate, n)) < 1.0E-30 ) then
error = 1 ! 如果绝对值最大为0, 则矩阵不满秩, 无解
return ! 退出运算
end if
if ( maxLocate /= n ) then ! 如果绝对值最大值位置发生了变化, 则交换
do i = 1, m
temp = matrixInput(maxLocate, i)
matrixInput(maxLocate, i) = matrixInput(n, i)
matrixInput(n, i) = temp
end do
temp = arrayX(maxLocate)
arrayX(maxLocate) = arrayX(n)
arrayX(n) = temp
end if
do i = 1, m ! 消去其他行所有第n列的系数
if ( i /= n ) then
temp = -matrixInput(i, n)/matrixInput(n, n) ! 这里务必要设置一个临时值保存数值, 不然会被修改
matrixInput(i, :) = matrixInput(i, :) + matrixInput(n, :)*temp
arrayX(i) = arrayX(i) + arrayX(n)*temp
end if
end do
end do
do i = 1, m ! 产生X的解向量
arrayX(i) = arrayX(i)/matrixInput(i, i)
matrixInput(i, i) = 1.
end do
error = 0
end subroutine GaussAdamElimination
end module Chapter9
! ==============================================================================
! 主程序:
program ProName
! use ModName
implicit none
! 数据字典
! 声明常量
! 声明变量
! 变量初始化
! 数据输入
! 运算过程
! 结果输出
! call Exercises9_4
! call Exercises9_6
! call Exercises9_8
! call Exercises9_9
! call Exercises9_11
! call Exercises9_12
! call Exercises9_13
! call Exercises9_14
! call Exercises9_15
! call Exercises9_16
end program ProName
! ==============================================================================
! 子程序
! subroutine SubName(varName1,varName2)
! use MouName
! implicit none
! Type, intent(inout) :: varName
! end subroutine SubName
! ==============================================================================
! 函数
! function FunName(varName1,varName2)
! use MouName
! implicit none
! end function FunName
! ==============================================================================
! 习题9-4 判断程序正误
subroutine Exercises9_4
implicit none
real :: a=3., b=4., output
integer :: i=0
call sub1(a, I, output)
write(*,*) 'The output is', output
contains
subroutine sub1(x, j, junk)
real, intent(in) :: x
integer, intent(in) :: j
real, intent(out) :: junk
junk = (x-j)/b
end subroutine sub1
end subroutine Exercises9_4
subroutine Exercises9_6
implicit none
real, dimension(:, :), allocatable :: arrayInput1, arrayInput2, arrayResult ! 输入输出矩阵
integer :: errorLevel ! 错误码
integer :: i ! 循环参数
! 9-6 a
allocate(arrayInput1(3, 3), stat=errorLevel) ! 分配数组
if (errorLevel /= 0) print *, "arrayInput1: Allocation request denied"
allocate(arrayInput2(3, 3), stat=errorLevel)
if (errorLevel /= 0) print *, "arrayInput2: Allocation request denied"
allocate(arrayResult(3, 3), stat=errorLevel)
if (errorLevel /= 0) print *, "arrayResult: Allocation request denied"
arrayInput1(1, :) = (/ 2., -1., 2./) ! 定义数组
arrayInput1(2, :) = (/-1., -3., 4./)
arrayInput1(3, :) = (/ 2., 4., 2./)
arrayInput2(1, :) = (/ 1., 2., 3./)
arrayInput2(2, :) = (/ 2., 1., 2./)
arrayInput2(3, :) = (/ 3., 2., 1./)
call MatrixMultplication(arrayInput1, 3, 3, arrayInput2, 3, 3, arrayResult, errorLevel) ! 调用子程序计算矩阵乘积
if (errorLevel /= 0) print *, "无法进行矩阵乘法"
write(*,'(3F8.2)') (arrayResult(i, :), i = 1, 3) ! 输出计算结果
arrayResult(:,:) = matmul(arrayInput1, arrayInput2) ! 调用内部函数计算矩阵乘积
write(*,'(3F8.2)') (arrayResult(i, :), i = 1, 3) ! 输出计算结果
call MatrixMul(arrayInput1, arrayInput2, arrayResult, errorLevel) ! 调用子程序计算矩阵乘积
if (errorLevel /= 0) print *, "无法进行矩阵乘法"
write(*,'(3F8.2)') (arrayResult(i, :), i = 1, 3) ! 输出计算结果
if (allocated(arrayResult)) deallocate(arrayResult, stat=errorLevel) ! 释放数组
if (errorLevel /= 0) print *, "arrayResult: Deallocation request denied"
if (allocated(arrayInput2)) deallocate(arrayInput2, stat=errorLevel)
if (errorLevel /= 0) print *, "arrayInput2: Deallocation request denied"
if (allocated(arrayInput1)) deallocate(arrayInput1, stat=errorLevel)
if (errorLevel /= 0) print *, "arrayInput1: Deallocation request denied"
! 9-6 b
allocate(arrayInput1(4, 3), stat=errorLevel) ! 分配数组
if (errorLevel /= 0) print *, "arrayInput1: Allocation request denied"
allocate(arrayInput2(3, 1), stat=errorLevel)
if (errorLevel /= 0) print *, "arrayInput2: Allocation request denied"
allocate(arrayResult(4, 1), stat=errorLevel)
if (errorLevel /= 0) print *, "arrayResult: Allocation request denied"
arrayInput1(1, :) = (/ 1., -1., -2./) ! 定义数组
arrayInput1(2, :) = (/ 2., 2., 0./)
arrayInput1(3, :) = (/ 3., 3., 3./)
arrayInput1(4, :) = (/ 5., 4., 4./)
arrayInput2(:, 1) = (/-2., 5., 2./)
call MatrixMultplication(arrayInput1, 4, 3, arrayInput2, 3, 1, arrayResult, errorLevel) ! 调用子程序计算矩阵乘积
if (errorLevel /= 0) print *, "无法进行矩阵乘法"
write(*,'(F8.2)') (arrayResult(i, :), i = 1, 4) ! 输出计算结果
arrayResult(:,:) = matmul(arrayInput1, arrayInput2) ! 调用内部函数计算矩阵乘积
write(*,'(F8.2)') (arrayResult(i, :), i = 1, 4) ! 输出计算结果
call MatrixMul(arrayInput1, arrayInput2, arrayResult, errorLevel) ! 调用子程序计算矩阵乘积
if (errorLevel /= 0) print *, "无法进行矩阵乘法"
write(*,'(F8.2)') (arrayResult(i, :), i = 1, 4) ! 输出计算结果
if (allocated(arrayResult)) deallocate(arrayResult, stat=errorLevel) ! 释放数组
if (errorLevel /= 0) print *, "arrayResult: Deallocation request denied"
if (allocated(arrayInput2)) deallocate(arrayInput2, stat=errorLevel)
if (errorLevel /= 0) print *, "arrayInput2: Deallocation request denied"
if (allocated(arrayInput1)) deallocate(arrayInput1, stat=errorLevel)
if (errorLevel /= 0) print *, "arrayInput1: Deallocation request denied"
contains
! 矩阵乘法子程序, 显式结构
subroutine MatrixMultplication(array1, x1, y1, array2, x2, y2, array3, errorLevel)
integer, intent(in) :: x1, y1, x2, y2 ! 矩阵大小
real, dimension(x1, y1), intent(in) :: array1 ! 矩阵1
real, dimension(x2, y2), intent(in) :: array2 ! 矩阵2
real, dimension(x1, y2), intent(out) :: array3 ! 输出矩阵
integer, intent(out) :: errorLevel ! 错误代码
integer :: i, j, k ! 循环参数
if ( y1 /= x2 ) then ! 判断乘法是否可行
errorLevel = 1 ! 不可行, 错误码=1
return ! 退出
end if
array3 = 0. ! 初始化输出矩阵
! forall(i = 1:x1, j = 1:y1, k = 1:y2) ! forall结构计算
! array3(i, k) = array1(i, j)*array2(j, k) + array3(i, k)
! end forall
do i = 1, x1 ! do嵌套计算
do j = 1, y1
do k = 1, y2
array3(i, k) = array1(i, j)*array2(j, k) + array3(i, k)
end do
end do
end do
errorLevel = 0 ! 运算完成, 错误码=0
end subroutine MatrixMultplication
! 矩阵乘法子程序, 显式接口不定结构
subroutine MatrixMul(array1, array2, array3, errorLevel)
real, dimension(:, :), intent(in) :: array1 ! 矩阵1
real, dimension(:, :), intent(in) :: array2 ! 矩阵2
real, dimension(:, :), intent(out) :: array3 ! 输出矩阵
integer, intent(out) :: errorLevel ! 错误代码
integer :: i, j, k ! 循环参数
if ( size(array1, 2) /= size(array2, 1) ) then ! 判断乘法是否可行
errorLevel = 1 ! 不可行, 错误码=1
return ! 退出
end if
array3 = 0. ! 初始化输出矩阵
! forall(i = 1:x1, j = 1:y1, k = 1:y2) ! forall结构计算
! array3(i, k) = array1(i, j)*array2(j, k) + array3(i, k)
! end forall
do i = 1, size(array1, 1) ! do嵌套计算
do j = 1, size(array1, 2)
do k = 1, size(array2, 2)
array3(i, k) = array1(i, j)*array2(j, k) + array3(i, k)
end do
end do
end do
errorLevel = 0 ! 运算完成, 错误码=0
end subroutine MatrixMul
end subroutine Exercises9_6
! 习题9-8
subroutine Exercises9_8
implicit none
real, dimension(3, 3) :: arrayInput1, arrayInput2 ! 输入矩阵
real, dimension(3) :: arrayX1, arrayX2 ! 常数向量
integer :: errorLevel ! 错误码
integer :: i ! 循环参数
arrayInput1(1, :) = (/ 1.0, 1.0, 1.0/) ! 输入数据1
arrayInput1(2, :) = (/ 2.0, 1.0, 1.0/)
arrayInput1(3, :) = (/ 1.0, 3.0, 2.0/)
arrayX1(:) = (/ 1.0, 2.0, 4.0/)
arrayInput2(1, :) = (/ 1.0, 1.0, 1.0/) ! 输入数据2
arrayInput2(2, :) = (/ 2.0, 6.0, 4.0/)
arrayInput2(3, :) = (/ 1.0, 3.0, 2.0/)
arrayX2(:) = (/ 1.0, 8.0, 4.0/)
call GAEli(arrayInput1, arrayX1, errorLevel) ! 调用子程序解方程组
if (errorLevel /= 0) then
write(*,*) 'Error!' ! 如果无解, 输出错误
else
write(*,'(4F8.2)') (arrayInput1(i, :), arrayX1(i), i = 1, 3) ! 如果有解, 输出计算后的矩阵
end if
call GAEli(arrayInput2, arrayX2, errorLevel) ! 调用子程序解方程组
if (errorLevel /= 0) then
write(*,*) 'Error!' ! 如果无解, 输出错误
else
write(*,'(4F8.2)') (arrayInput2(i, :), arrayX2(i), i = 1, 3) ! 如果有解, 输出计算后的矩阵
end if
contains
! 高斯亚当消元法, 不定结构, 破坏输入矩阵
subroutine GAEli(matrixInput, arrayX, errorLevel)
implicit none
real, dimension(:, :), intent(inout) :: matrixInput ! 输入矩阵(输入)
real, dimension(:), intent(inout) :: arrayX ! 输入常数向量, 输出X解向量
integer, intent(out) :: errorLevel ! 错误值
real :: temp ! 临时值, 用于数值交换
integer :: maxLocate ! 最大值所在行
integer :: i, n, m ! 局部变量: 循环参数
m = size(matrixInput, 1)
do n = 1, m
maxLocate = n ! 初始化绝对值最大的位置
do i = n+1, m ! 执行最大支点技术,减少舍入误差
if ( abs(matrixInput(i, n)) > abs(matrixInput(maxLocate, n)) ) then
maxLocate = i
end if
end do
if ( abs(matrixInput(maxLocate, n)) < 1.0E-30 ) then
errorLevel = 1 ! 如果绝对值最大为0, 则矩阵不满秩, 无解
return ! 退出运算
end if
if ( maxLocate /= n ) then ! 如果绝对值最大值位置发生了变化, 则交换
do i = 1, m
temp = matrixInput(maxLocate, i)
matrixInput(maxLocate, i) = matrixInput(n, i)
matrixInput(n, i) = temp
end do
temp = arrayX(maxLocate)
arrayX(maxLocate) = arrayX(n)
arrayX(n) = temp
end if
do i = 1, m ! 消去其他行所有第n列的系数
if ( i /= n ) then
temp = -matrixInput(i, n)/matrixInput(n, n) ! 这里务必要设置一个临时值保存数值, 不然会被修改
matrixInput(i, :) = matrixInput(i, :) + matrixInput(n, :)*temp
arrayX(i) = arrayX(i) + arrayX(n)*temp
end if
end do
end do
do i = 1, m ! 产生X的解向量
arrayX(i) = arrayX(i)/matrixInput(i, i)
matrixInput(i, i) = 1.
end do
errorLevel = 0
end subroutine GAEli
end subroutine Exercises9_8
! 习题9-8
subroutine Exercises9_9
implicit none
real, dimension(3, 3) :: arrayInput1, arrayInput2 ! 输入矩阵
real, dimension(3) :: arrayX1, arrayX2 ! 常数向量
integer :: errorLevel ! 错误码
integer :: i ! 循环参数
arrayInput1(1, :) = (/ 1.0, 1.0, 1.0/) ! 输入数据1
arrayInput1(2, :) = (/ 2.0, 1.0, 1.0/)
arrayInput1(3, :) = (/ 1.0, 3.0, 2.0/)
arrayX1(:) = (/ 1.0, 2.0, 4.0/)
arrayInput2(1, :) = (/ 1.0, 1.0, 1.0/) ! 输入数据2
arrayInput2(2, :) = (/ 2.0, 6.0, 4.0/)
arrayInput2(3, :) = (/ 1.0, 3.0, 2.0/)
arrayX2(:) = (/ 1.0, 8.0, 4.0/)
call GAEli1(arrayInput1, arrayX1, errorLevel) ! 调用子程序解方程组
if (errorLevel /= 0) then
write(*,*) 'Error!' ! 如果无解, 输出错误
else
write(*,'(A, I1, A, F6.2)') ('x', i, ' = ', arrayX1(i), i = 1, 3) ! 如果有解, 输出各解
end if
call GAEli1(arrayInput2, arrayX2, errorLevel) ! 调用子程序解方程组
if (errorLevel /= 0) then
write(*,*) 'Error!' ! 如果无解, 输出错误
else
write(*,'(A, I1, F6.2)') ('x', i, ' = ', arrayX2(i), i = 1, 3) ! 如果有解, 输出各解
end if
contains
! 高斯-亚当消元法,不破坏输入矩阵
subroutine GAEli1(matrixInput1, arrayX, errorLevel)
implicit none
real, dimension(:, :), intent(inout) :: matrixInput1 ! 输入矩阵(输入)
real, dimension(size(matrixInput1, 1), size(matrixInput1, 2)) :: matrixInput
! 运算矩阵
real, dimension(:), intent(inout) :: arrayX ! 输入常数向量, 输出X解向量
integer, intent(out) :: errorLevel ! 错误值
real :: temp ! 临时值, 用于数值交换
integer :: maxLocate ! 最大值所在行
integer :: i, n, m ! 局部变量: 循环参数
matrixInput = matrixInput1
m = size(matrixInput, 1)
do n = 1, m
maxLocate = n ! 初始化绝对值最大的位置
do i = n+1, m ! 执行最大支点技术,减少舍入误差
if ( abs(matrixInput(i, n)) > abs(matrixInput(maxLocate, n)) ) then
maxLocate = i
end if
end do
if ( abs(matrixInput(maxLocate, n)) < 1.0E-30 ) then
errorLevel = 1 ! 如果绝对值最大为0, 则矩阵不满秩, 无解
return ! 退出运算
end if
if ( maxLocate /= n ) then ! 如果绝对值最大值位置发生了变化, 则交换
do i = 1, m
temp = matrixInput(maxLocate, i)
matrixInput(maxLocate, i) = matrixInput(n, i)
matrixInput(n, i) = temp
end do
temp = arrayX(maxLocate)
arrayX(maxLocate) = arrayX(n)
arrayX(n) = temp
end if
do i = 1, m ! 消去其他行所有第n列的系数
if ( i /= n ) then
temp = -matrixInput(i, n)/matrixInput(n, n) ! 这里务必要设置一个临时值保存数值, 不然会被修改
matrixInput(i, :) = matrixInput(i, :) + matrixInput(n, :)*temp
arrayX(i) = arrayX(i) + arrayX(n)*temp
end if
end do
end do
do i = 1, m ! 产生X的解向量
arrayX(i) = arrayX(i)/matrixInput(i, i)
matrixInput(i, i) = 1.
end do
errorLevel = 0
end subroutine GAEli1
end subroutine Exercises9_9
! 习题9-11 9-12
subroutine Exercises9_11
implicit none
real, allocatable, dimension(:) :: a
integer :: istat
allocate(a(6), stat=istat)
a = (/ 1., 2., 3., 4., 5., 6./)
write(*,'(A, 6F4.1)') 'Main: Array a before call = ', a
call test_alloc(a)
write(*,'(A, 6F4.1)') 'Main: Array a after call = ', a
contains
subroutine test_alloc(array)
real, dimension(:), allocatable, intent(inout) :: array
integer :: i
integer :: istat
if (allocated(array)) then
write(*,'(A)') 'Sub: the array is allocated'
write(*,'(A, 6F4.1)') 'Sub: Array on entry = ', array
else
write(*,*) 'In sub: the array is not allocated'
end if
if (allocated(array)) then
deallocate(array, stat=istat)
end if
allocate(array(5), stat=istat)
do i = 1, 5
array(i) = 6 - i
end do
write(*,'(A, 6F4.1)') 'Sub: Array on exit = ', array
end subroutine test_alloc
end subroutine Exercises9_11
! 习题9-13 掷色子
subroutine Exercises9_13
implicit none
integer :: x, y ! 定义俩变量
call throw(x, y) ! 获取俩随机值
write(*,*) x, y ! 打印
contains
subroutine throw(random1, random2) ! out属性形参可以作为参数传递给过程
integer, intent(out) :: random1, random2 ! 定义俩变量储存随机数
call die(random1) ! 获取第一个随机数
call die(random2) ! 获取第二个随机数
end subroutine throw
subroutine die(random)
integer, intent(out) :: random ! 定义随机整数
real :: temp ! 随机数临时值
call random_seed() ! 根据时间日期获取随机数种子
call random_number(temp) ! 获取一个[0,1)的随机数给临时值
random = int(temp*6) + 1 ! 变化其区间为[1,7), 并向下取整
end subroutine die
end subroutine Exercises9_13
! 创建逐元过程运算, 这种过程内函数, 直接在函数体写定义, 调用部分可以不考虑
subroutine Exercises9_14
implicit none
real, parameter :: PI=3.14159265 ! PI值
real, dimension(2, 3) :: array1, array2, array3 ! 计算用数组
integer :: i ! 循环参数
array1(1, :) = (/ 10.0, 20.0, 30.0/) ! 定义输入数组
array1(2, :) = (/ 40.0, 50.0, 60.0/)
array2 = FunSin(array1) ! 计算值
write(*,1) '计算得到正弦值为:', (array2(i, :), i = 1, 2) ! 输出计算值, 以下相同
array3 = FunAsin(array2)
write(*,1) '计算得到反正弦值为:', (array3(i, :), i = 1, 2)
array2 = FunCos(array1)
write(*,1) '计算得到余弦值为:', (array2(i, :), i = 1, 2)
array3 = FunAcos(array2)
write(*,1) '计算得到反余弦值为:', (array3(i, :), i = 1, 2)
array2 = FunTan(array1)
write(*,1) '计算得到正切为:', (array2(i, :), i = 1, 2)
array3 = FunAtan(array2)
write(*,1) '计算得到反正切为:', (array3(i, :), i = 1, 2)
1 format(1X, A,/& ! 输出格式
&1X, 3F8.2,/&
&1X, 3F8.2)
contains
elemental function FunSin(degree) ! 定义函数
real, intent(in) :: degree ! 定义输入变量
real :: FunSin ! 定义函数输出类型
FunSin = sin(degree/360.*2*PI) ! 计算输出值, 以下相同
end function FunSin
elemental function FunCos(degree)
real, intent(in) :: degree
real :: FunCos
FunCos = cos(degree/360.*2*PI)
end function FunCos
elemental function FunTan(degree)
real, intent(in) :: degree
real :: FunTan
FunTan = tan(degree/360.*2*PI)
end function FunTan
elemental function FunAsin(value)
real, intent(in) :: value
real :: FunAsin
FunAsin = asin(value)*360./(2.*PI)
end function FunAsin
elemental function FunAcos(value)
real, intent(in) :: value
real :: FunAcos
FunAcos = acos(value)*360./(2.*PI)
end function FunAcos
elemental function FunAtan(value)
real, intent(in) :: value
real :: FunAtan
FunAtan = atan(value)*360./(2.*PI)
end function FunAtan
end subroutine Exercises9_14
! 习题9-15 将9-14的内容修改为纯函数
subroutine Exercises9_15
implicit none
real, parameter :: PI=3.14159265 ! PI值
real, dimension(2, 3) :: array1, array2, array3 ! 计算用数组
integer :: i ! 循环参数
array1(1, :) = (/ 10.0, 20.0, 30.0/) ! 定义输入数组
array1(2, :) = (/ 40.0, 50.0, 60.0/)
array2 = FunSin(array1) ! 计算值
write(*,1) '计算得到正弦值为:', (array2(i, :), i = 1, 2) ! 输出计算值, 以下相同
array3 = FunAsin(array2)
write(*,1) '计算得到反正弦值为:', (array3(i, :), i = 1, 2)
array2 = FunCos(array1)
write(*,1) '计算得到余弦值为:', (array2(i, :), i = 1, 2)
array3 = FunAcos(array2)
write(*,1) '计算得到反余弦值为:', (array3(i, :), i = 1, 2)
array2 = FunTan(array1)
write(*,1) '计算得到正切为:', (array2(i, :), i = 1, 2)
array3 = FunAtan(array2)
write(*,1) '计算得到反正切为:', (array3(i, :), i = 1, 2)
1 format(1X, A,/& ! 输出格式
&1X, 3F8.2,/&
&1X, 3F8.2)
contains
pure function FunSin(degree)
real, intent(in), dimension(:, :) :: degree
real, dimension(size(degree, 1), size(degree, 2)) :: FunSin
FunSin = sin(degree/360.*2*PI)
end function FunSin
pure function FunCos(degree)
real, intent(in), dimension(:, :) :: degree
real, dimension(size(degree, 1), size(degree, 2)) :: FunCos
FunCos = cos(degree/360.*2*PI)
end function FunCos
pure function FunTan(degree)
real, intent(in), dimension(:, :) :: degree
real, dimension(size(degree, 1), size(degree, 2)) :: FunTan
FunTan = tan(degree/360.*2*PI)
end function FunTan
pure function FunAsin(value)
real, intent(in), dimension(:, :) :: value
real, dimension(size(value, 1), size(value, 2)) :: FunAsin
FunAsin = asin(value)*360./(2.*PI)
end function FunAsin
pure function FunAcos(value)
real, intent(in), dimension(:, :) :: value
real, dimension(size(value, 1), size(value, 2)) :: FunAcos
FunAcos = acos(value)*360./(2.*PI)
end function FunAcos
pure function FunAtan(value)
real, intent(in), dimension(:, :) :: value
real, dimension(size(value, 1), size(value, 2)) :: FunAtan
FunAtan = atan(value)*360./(2.*PI)
end function FunAtan
end subroutine Exercises9_15
! 习题9-16 高阶最小二乘回归 首先第一个,发现了解多元一次方程组程序的错误,第二,发现了总之,很多很多错误,很有意义的一道题
subroutine Exercises9_16
implicit none
real, dimension(:), allocatable :: pointX, pointY ! 坐标(x, y)
real, dimension(:), allocatable :: arrayCoefficient ! 系数向量
integer :: errorLevel ! 错误码
integer :: i ! 循环参数
real :: temp
open(unit=1, status='scratch', iostat=errorLevel) ! 打开临时文件
if ( errorLevel /= 0 ) stop "打开临时文件失败" ! 判断打开状态
write(1, '(A)') & ! 输入数据
&' 0.167, 0.333, 0.500, 0.667, 0.833, 1.000, 1.167, 1.333, 1.500&
&, 1.667, 1.833, 2.000, 2.167, 2.333, 2.500, 2.667, 2.833, 3.000',&
&' 49.9, 52.2, 50.6, 47.0, 47.7, 42.3, 37.9, 38.2, 38.0, 33.8, 26.7, 24.8, 22.0, 16.5, 14.0, 5.6, 2.9, 0.8',&
&' -5.1,-12.9,-15.1, -6.8,-12.3,-18.0, -5.7, -6.3,-12.7,-13.7,-26.7,-31.3,-22.9,-25.6,-25.7,-25.2,-35.0,-27.9'
rewind(unit=1, iostat=errorLevel) ! 回到初始行
if ( errorLevel /= 0 ) stop "读取临时文件失败" ! 判断执行状态
allocate(pointX(18), stat=errorLevel) ! 分配数组
if (errorLevel /= 0) print *, "pointX: Allocation request denied" ! 判断分配结果, 下同
allocate(pointY(18), stat=errorLevel)
if (errorLevel /= 0) print *, "pointY: Allocation request denied"
allocate(arrayCoefficient(3), stat=errorLevel)
if (errorLevel /= 0) print *, "arrayCoefficient: Allocation request denied"
read(1, *) pointX, pointY ! 读取数据
close(unit=1, iostat=errorLevel) ! 关闭临时文件
if ( errorLevel /= 0 ) stop "关闭临时文件失败" ! 判断关闭状态
! write(*,'(18(F8.2, 1X))') pointX, pointY ! 输出读入值(供检验, 可注释)
call MultipleRegression(pointX, pointY, arrayCoefficient, 2, errorLevel) ! 计算参数值
write(*,*) '习题9-16'
write(*,1) arrayCoefficient ! 输出结果
1 format(1X, '(?) 计算得到的方程为h = ', F8.2, ' + ', F8.2, ' t + ', F8.2, ' t^2')
! 习题9-17
write(*,*) '习题9-17'
call ShowNoise2( 0.0, 0.0, '(a)')
call ShowNoise2(-0.1, 0.1, '(b)')
call ShowNoise2(-0.5, 0.5, '(c)')
call ShowNoise2(-1.0, 1.0, '(d)')
! 习题9-19
write(*,*) '习题9-19'
arrayCoefficient = (/0.0, 0.0, 0.0, 0.0, 0.0/) ! 重定义系数向量长度
call ShowNoise4( 0.0, 0.0, '(a)')
call ShowNoise4(-0.1, 0.1, '(b)')
call ShowNoise4(-0.5, 0.5, '(c)')
call ShowNoise4(-1.0, 1.0, '(d)')
! 习题9-20
write(*,*) '习题9-20'
open(unit=1, status='scratch', iostat=errorLevel) ! 打开临时文件
if ( errorLevel /= 0 ) stop "打开临时文件失败" ! 判断打开状态
write(1, '(A)') & ! 输入数据
&' 0.00, 1.00, 2.00, 3.00, 4.00, 5.00, 6.00, 7.00, 8.00, 9.00, 10.00',&
&'-23.22,-13.54, -4.14, -0.04, 3.92, 4.97, 3.96, -0.07, -5.67,-12.28,-20.25'
rewind(unit=1, iostat=errorLevel) ! 回到初始行
if ( errorLevel /= 0 ) stop "关闭临时文件失败" ! 判断关闭状态
pointX = (/(i, i = 1, 10)/) ! 重定义坐标x向量长度
pointY = pointX ! 重定义坐标y向量长度
read(1,*) pointX, pointY ! 赋值坐标(x, y)
close(unit=1, iostat=errorLevel) ! 关闭临时文件
arrayCoefficient = (/0.0, 0.0, 0.0/) ! 重定义系数向量长度
call MultipleRegression(pointX, pointY, arrayCoefficient, 2, errorLevel) ! 计算参数值
write(*,4) arrayCoefficient ! 输出结果
4 format(1X, '(?) 计算得到的方程为y = ', F8.2, ' + ', F8.2, ' x + ', F8.2, ' x^2')
write(*,*) ' 当x0取3.5时得到y0 = ', arrayCoefficient(1) + arrayCoefficient(2)*3.5 + arrayCoefficient(3)*3.5**2
! 习题9-21
write(*,*) '习题9-21'
open(unit=1, status='scratch', iostat=errorLevel) ! 打开临时文件
if ( errorLevel /= 0 ) stop "打开临时文件失败" ! 判断打开状态
write(1, '(A)') & ! 输入数据
&' 0.00, 1.00, 2.00, 3.00, 4.00, 5.00, 6.00, 7.00, 8.00, 9.00, 10.00',&
&'-14.22,-10.54, -5.09, -3.12, 0.92, 3.79, 6.99, 8.95, 11.33, 14.71, 18.75'
rewind(unit=1, iostat=errorLevel) ! 回到初始行
if ( errorLevel /= 0 ) stop "关闭临时文件失败" ! 判断关闭状态
pointX = (/(i, i = 1, 10)/) ! 重定义坐标x向量长度
pointY = pointX ! 重定义坐标y向量长度
read(1,*) pointX, pointY ! 赋值坐标(x, y)
close(unit=1, iostat=errorLevel) ! 关闭临时文件
arrayCoefficient = (/0.0, 0.0, 0.0/) ! 重定义系数向量长度
call MultipleRegression(pointX, pointY, arrayCoefficient, 2, errorLevel) ! 计算参数值
write(*,4) arrayCoefficient ! 输出结果
write(*,*) ' 当x0取14.0时得到y0 = ', arrayCoefficient(1) + arrayCoefficient(2)*14.0 + arrayCoefficient(3)*14.0**2
if ( errorLevel /= 0 ) stop "读取临时文件失败" ! 判断执行状态
if (allocated(arrayCoefficient)) deallocate(arrayCoefficient, stat=errorLevel) ! 释放数组
if (errorLevel /= 0) print *, "arrayCoefficient: Deallocation request denied" ! 判断释放结果, 下同
if (allocated(pointY)) deallocate(pointY, stat=errorLevel)
if (errorLevel /= 0) print *, "pointY: Deallocation request denied"
if (allocated(pointX)) deallocate(pointX, stat=errorLevel)
if (errorLevel /= 0) print *, "pointX: Deallocation request denied"
contains
! 构建输入方程和解向量
subroutine MultipleRegression(arrayX, arrayY, arrayResult, order, errorLevel)
real, dimension(:), intent(in) :: arrayX, arrayY ! 输入坐标(x, y)
integer, intent(in) :: order ! 拟合阶数
real, dimension(order+1), intent(out) :: arrayResult ! 系数向量(同时也充当了常数向量)
real, dimension(order+1, order+1) :: matrixCoefficient ! 系数矩阵
integer, intent(out) :: errorLevel ! 错误码(虽然主程序中没有做错误校验就是)
integer :: i, j ! 循环参数
if ( order < 1 ) then ! 判断阶数是否符合要求
errorLevel = 1
return
else
do i = 1, order+1 ! 各参数的偏导方程
do j = 1, order+1 ! 某一参数偏导数取0时, 各系数
matrixCoefficient(i, j) = sum(arrayX**(i+j-2)) ! 给各系数赋值
end do
arrayResult(i) = sum(arrayX**(i-1)*arrayY) ! 给常数向量赋值
end do
! write(*,'(3(F8.2, 1X))') matrixCoefficient, arrayResult ! 打印系数矩阵和常数向量(共检验, 可注释)
call GAEli1(matrixCoefficient, arrayResult, errorLevel) ! 计算系数值
end if
end subroutine MultipleRegression
! 调用方程组求解子程序,高斯-亚当消元法(不破坏输入数组)
subroutine GAEli1(matrixInput1, arrayX, errorLevel)
implicit none
real, dimension(:, :), intent(inout) :: matrixInput1 ! 输入矩阵(输入)
real, dimension(size(matrixInput1, 1), size(matrixInput1, 2)) :: matrixInput
! 运算矩阵
real, dimension(:), intent(inout) :: arrayX ! 输入常数向量, 输出X解向量
integer, intent(out) :: errorLevel ! 错误值
real :: temp ! 临时值, 用于数值交换
integer :: maxLocate ! 最大值所在行
integer :: i, n, m ! 局部变量: 循环参数
matrixInput = matrixInput1
m = size(matrixInput, 1)
do n = 1, m
maxLocate = n ! 初始化绝对值最大的位置
do i = n+1, m ! 执行最大支点技术,减少舍入误差
if ( abs(matrixInput(i, n)) > abs(matrixInput(maxLocate, n)) ) then
maxLocate = i
end if
end do
if ( abs(matrixInput(maxLocate, n)) < 1.0E-30 ) then
errorLevel = 1 ! 如果绝对值最大为0, 则矩阵不满秩, 无解
return ! 退出运算
end if
if ( maxLocate /= n ) then ! 如果绝对值最大值位置发生了变化, 则交换
do i = 1, m
temp = matrixInput(maxLocate, i)
matrixInput(maxLocate, i) = matrixInput(n, i)
matrixInput(n, i) = temp
end do
temp = arrayX(maxLocate)
arrayX(maxLocate) = arrayX(n)
arrayX(n) = temp
end if
do i = 1, m ! 消去其他行所有第n列的系数
if ( i /= n ) then
temp = -matrixInput(i, n)/matrixInput(n, n) ! 这里务必要设置一个临时值保存数值, 不然会被修改
matrixInput(i, :) = matrixInput(i, :) + matrixInput(n, :)*temp
arrayX(i) = arrayX(i) + arrayX(n)*temp
end if
end do
end do
do i = 1, m ! 产生X的解向量
arrayX(i) = arrayX(i)/matrixInput(i, i)
matrixInput(i, i) = 1.
end do
errorLevel = 0
end subroutine GAEli1
! 用于产生噪声值
subroutine Noise(value, lowerBound, upperBound)
real, intent(out) :: value ! 输出的随机数值
real, intent(in) :: lowerBound, upperBound ! 输出随机数值的上下界, 范围是[lowerBound, upperBound)
call random_seed() ! 根据当前时间日期计算随机数种子
call random_number(value) ! 计算随机数
value = lowerBound + value*( upperBound - lowerBound ) ! 重分布以适应范围
end subroutine Noise
! 用于计算习题9-17, 这里采用的是二阶回归
subroutine ShowNoise2(lowerBound, upperBound, tag)
real, intent(in) :: lowerBound, upperBound ! 噪声值上下界
character(len=3), intent(in) :: tag ! 当前题目标识符
pointX = (/0.0, 1.0, 2.0, 3.0, 4.0, 5.0/) ! 赋值坐标x
do i = 1, 6
call Noise(temp, lowerBound, upperBound) ! 产生噪声值
pointY(i) = pointX(i)**2 - 4*pointX(i) + 3 + temp ! 赋值坐标y
end do
call MultipleRegression(pointX, pointY, arrayCoefficient, 2, errorLevel)! 计算参数值
write(*,2) trim(tag), arrayCoefficient ! 输出结果
2 format(1X, A,' 计算得到的方程为h = ', F8.2, ' + ', F8.2, ' t + ', F8.2, ' t^2')
end subroutine ShowNoise2
! 用于计算习题9-19, 这里采用的是四阶回归
subroutine ShowNoise4(lowerBound, upperBound, tag)
real, intent(in) :: lowerBound, upperBound ! 噪声值上下界
character(len=3), intent(in) :: tag ! 当前题目标识符
pointX = (/0.0, 1.0, 2.0, 3.0, 4.0, 5.0/) ! 赋值坐标x
do i = 1, 6
call Noise(temp, lowerBound, upperBound) ! 产生噪声值
pointY(i) = pointX(i)**4 - 3*pointX(i)**3 - 4*pointX(i)**2 + 2*pointX(i) + 3 + temp
end do ! 赋值坐标y
call MultipleRegression(pointX, pointY, arrayCoefficient, 4, errorLevel)! 计算参数值
write(*,3) trim(tag), arrayCoefficient ! 输出结果
3 format(1X, A,' 计算得到的方程为h = ', F8.2, ' + ', F8.2, ' t + ', F8.2,&
& ' t^2 + ', F8.2, ' t^3 + ', F8.2, ' t^4')
end subroutine ShowNoise4
end subroutine Exercises9_16