Files
Fortran-95-2003-Program-3rd…/第9章习题.f90
2025-09-25 16:33:13 +08:00

796 lines
49 KiB
Fortran
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

! ==============================================================================
! 通过 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