729 lines
30 KiB
Fortran
729 lines
30 KiB
Fortran
! ==============================================================================
|
|
! 通过 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 |