$ gfortran --version
GNU Fortran (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ gfortran-10 --version
GNU Fortran (Ubuntu 10.3.0-1ubuntu1~20.04) 10.3.0
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
ソース プログラム
module uniplot
implicitnoneprivatepublic :: fig_t
type :: fig_t
privateinteger :: nx, ny
integer, allocatable :: array(:, :)
containsprocedure :: init
procedure :: point
procedure :: show
procedure :: line0
procedure :: line
end type fig_t
containssubroutine init(fig, nx, ny)
class(fig_t), intent(out) :: fig
integer, intent(in) :: nx, ny
fig%nx = nx
fig%ny = ny
allocate(fig%array(0:(nx+1)/2, 0:(ny+3)/4) )
end subroutine init
subroutine point(fig, ix, iy)
class(fig_t), intent(inout) :: fig
integer, intent(in) :: ix, iy
integer :: iax, iay
iax = ix /2
iay = iy /4! clippingif (0<=ix .and. ix<fig%nx .and.0<=iy .and. iy<fig%ny) then
fig%array(iax, iay) =ior(fig%array(iax, iay), icode(mod(ix, 2), mod(iy, 4)))
end ifend subroutine point
pureelementalintegerfunction icode(kx, ky)
integer, intent(in) :: kx, ky
if (ky ==3) then
icode =64+64* kx
else! 0, 1, 2
icode =2**(ky +3*kx)
end ifend function icode
subroutine line0(fig, ix0, iy0, ix1, iy1)
class(fig_t), intent(inout) :: fig
integer, intent(in) :: ix0, iy0, ix1, iy1
integer :: i, ix, iy, nx, ny
real :: d
nx = ix1 - ix0
ny = iy1 - iy0
if (nx ==0.and. ny ==0) thencall fig%point(ix, iy)
elseif (abs(nx) <abs(ny)) then
d = nx /real(ny)
do i =0, abs(ny)
ix =nint(ix0 + d *sign(i, ny))
iy = iy0 +sign(i, ny)
call fig%point(ix, iy)
end doelse
d = ny /real(nx)
do i =0, abs(nx)
iy =nint(iy0 + d *sign(i, nx))
ix = ix0 +sign(i, nx)
call fig%point(ix, iy)
end doend ifend subroutine line0
subroutine show(fig)
class(fig_t), intent(in) :: fig
integer :: iy
do iy =0, ubound(fig%array, 2)
print'(*(a))', reverse_endian(shift_code(fig%array(:, iy)))
end doend subroutine show
pureelementalintegerfunction shift_code(k)
integer, intent(in) :: k
integer, parameter :: n0 = Z'E2A080'!14852224
shift_code = n0 +256* (k /64) +mod(k, 64) !E2A180, E2A280, E2A380 end function shift_code
pureelementalcharacter(len=4) function reverse_endian(i)
integer, intent(in) :: i
character:: tmp(4)
tmp =transfer(i, ' ', size=4)
reverse_endian =transfer(tmp(4:1:-1), ' ') !array 4 to len 4end function reverse_endian
subroutine line(fig, x, y, ipen)
class(fig_t), intent(inout) :: fig
real, intent(in) :: x, y
integer, intent(in) :: ipen
integer, save :: ix0 =0, iy0 =0integer :: ix, iy
real, parameter :: xn =80.0, yn =100.0, fx =1.0, fy =0.85
ix =nint( fx * x + xn)
iy =nint(-fy * y + yn)
if (ipen ==1) call fig%line0(ix0, iy0, ix, iy)
ix0 = ix
iy0 = iy
end subroutine line
end module uniplot
program uniplot_main
implicitnone real, allocatable :: x(:), y(:)
integer, parameter :: n =10**3allocate(x(n), y(n))
callrandom_seed()
callrandom_number(x)
callrandom_number(y)
plot: blockuse :: uniplot
type(fig_t) :: fig1
integer :: i, ix0, iy0, ix1, iy1, k
k =100print*print*, 'Monte Carlo: estimated pi =', 4.0*count(x**2+ y**2<1.0) / n
call fig1%init(k, k)
! draw boxcall fig1%line0(0, 0, k-1, 0)
call fig1%line0(0, 0, 0, k-1)
call fig1%line0(0, k-1, k-1, k-1)
call fig1%line0(k-1, 0, k-1, k-1)
! draw 1/4 circle
ix0 =0
iy0 =0do ix1 =0, k -1
iy1 = k -1-int(sqrt(real((k-1)**2- ix1**2)))
call fig1%line0(ix0, iy0, ix1, iy1)
ix0 = ix1
iy0 = iy1
end do! plot dotsdo i =1, n
call fig1%point(int(k * x(i)), int(k * y(i)))
end docall fig1%show()
end block plot
end program uniplot_main
requirement S(T, F0)
type :: T; end typefunction F0(x) result(z)
type(T), intent(in) :: x
type(T) :: z
end functionend requirement
新例
requirement binary_op(T, U, V, op)
type, deferred :: T, U, V
function op(x, y) result(z)
type(T), intent(in) :: x
type(U), intent(in) :: y
type(V) :: z
end functionend requirement
We implemented an initial prototype of Generics into LFortran from the FortranGenerics Subcommittee's draft. It works online as well. If you are interested in generics in Fortran, please go ahead and test it out. Instructions and more details:https://t.co/X9hgUx5yFx
requirement の中の function 名が漏れ出して、多重定義エラーになってしまうので名前を F0 に変えました。
module template_test_m
implicitnoneprivatepublic :: unary_t, binary_t
requirement S(T, F0)
type :: T; end typefunction F0(x) result(z)
type(T), intent(in) :: x
type(T) :: z
end functionend requirement
template unary_t(T, F0)
requires S(T, F0)
privatepublic :: unary_generic
containsfunction unary_generic(x) result(z)
type(T), intent(in) :: x
type(T) :: z
z = F0(x)
end functionend template
requirement R(T, F)
type :: T; end typefunction F(x, y) result(z)
type(T), intent(in) :: x, y
type(T) :: z
end functionend requirement
template binary_t(T, F)
requires R(T, F)
privatepublic :: binary_generic
containsfunction binary_generic(x, y) result(z)
type(T), intent(in) :: x, y
type(T) :: z
z = F(x, y)
end functionend template
contains realfunction func_minus_real(x) result(z)
real, intent(in) :: x
z =-x
end function realfunction func_add_real(x, y) result(z)
real, intent(in) :: x, y
z = x + y
end function realfunction func_sub_real(x, y) result(z)
real, intent(in) :: x, y
z = x - y
end function realfunction func_mul_real(x, y) result(z)
real, intent(in) :: x, y
z = x * y
end function realfunction func_div_real(x, y) result(z)
real, intent(in) :: x, y
z = x / y
end functionsubroutine test_template()
instantiate unary_t(real, func_minus_real), only: minus_real => unary_generic
instantiate binary_t(real, func_add_real), only: add_real => binary_generic
instantiate binary_t(real, func_sub_real), only: sub_real => binary_generic
instantiate binary_t(real, func_mul_real), only: mul_real => binary_generic
instantiate binary_t(real, func_div_real), only: div_real => binary_generic
real :: x, y
x =5.1
y =7.2print*, "The result is ", minus_real(x)
if (abs(minus_real(x) + x) >1e-5) error stopprint*, "The result is ", add_real(x, y)
if (abs(add_real(x, y) -12.3) >1e-5) error stopprint*, "The result is ", sub_real(x, y)
if (abs(sub_real(x, y) +2.1) >1e-5) error stopprint*, "The result is ", mul_real(x, y)
if (abs(mul_real(x, y) -36.72) >1e-2) error stopprint*, "The result is ", div_real(x, y)
if (abs(div_real(x, y) -0.7083333) >1e-6) error stopend subroutineend moduleprogram template_test
use template_test_m
implicitnonecall test_template()
end program template_test
The result is -5.099999904632568
The result is 12.299999237060547
The result is -2.0999999046325684
The result is 36.71999740600586
The result is 0.7083333134651184