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

932 lines
44 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 运行
! 程序名:
! 习题
! 目的:
!
! 修订记录:
! 日期 编程者 改动描述
! =================== ============= =====================================
! 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 堆排序
!