如何在 Fortran 中为用户定义的复数正确定义算术运算符重载?
How to define correctly arithmetic operator overloading for user defined complex number in fortran?
我的 IDE 是:Code::Blocks 20.03 (MinGW 9.2.0)
这是我的简单代码:
module mod_kompleks
use, intrinsic :: iso_c_binding, only : rp => c_double
implicit none
type, public :: kom_bro
private
real(rp) :: dio_rea
real(rp) :: dio_img
contains
procedure, private :: kom_bro_sab ! 16 line
generic, public :: operator(+) => kom_bro_sab ! 18 line
end type kom_bro
interface kom_bro
module procedure :: kom_bro_set
end interface kom_bro
contains
! procedure - kom_bro_set
type(kom_bro) function kom_bro_set(rea_part, img_part) result(bro_c)
real, intent(in) :: rea_part, img_part
bro_c%dio_rea = rea_part
bro_c%dio_img = img_part
end function kom_bro_set
! procedure - kom_bro_sab
function kom_bro_sab(bro_a, bro_b) result(bro_c)
type(kom_bro), intent(in) :: bro_a
type(kom_bro), intent(in) :: bro_b
type(kom_bro) :: bro_c
bro_c%dio_rea = bro_a%dio_rea + bro_b%dio_rea
bro_c%dio_img = bro_a%dio_img + bro_b%dio_img
end function kom_bro_sab
end module mod_kompleks
program kompleksni_broj
use, non_intrinsic :: mod_kompleks
implicit none
integer :: i
type(kom_bro) :: broj_01(3)
type(kom_bro) :: broj_02(3)
type(kom_bro) :: broj_03(3)
do i = 1, 3
broj_01(i) = kom_bro(i + 2.2,i + 3.3)
broj_02(i) = kom_bro(i + 4.4,i + 5.5)
broj_03(i) = broj_01(i) + broj_02(i)
end do
end program kompleksni_broj
我打算定义一个看起来像复数但也允许将两个复数相加的算术运算的用户类型。由于我在示例中没有使用 Fortran 编程语言的经验,因此我遇到了编译器向我报告以下错误的问题:
|16|Error: Non-polymorphic passed-object dummy argument of 'kom_bro_sab'
|18|Error: Undefined specific binding 'kom_bro_sab' as target of GENERIC '+'
||=== Build failed: 2 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|
我对编程语言 Fortran 中的 OOP 的了解不足以让我自己解决这个问题。
甚至可以定义这样的用户定义类型吗?
您有多个错误。最重要的是运算符重载是错误的。请参阅下面我的示例实现。
复数的派生数据类型(文件名b.f90
)
module mod_kompleks
use, intrinsic :: iso_c_binding, only : rp => c_double
implicit none
private
public kom_bro
public operator(+)
type kom_bro
private
real(rp) :: dio_rea
real(rp) :: dio_img
contains
procedure :: init => kom_bro_init
procedure :: print => kom_bro_print
end type
interface operator(+)
module procedure kom_bro_sab
end interface
interface kom_bro
module procedure kom_bro_init2
end interface
contains
function kom_bro_init2(rea_part, img_part) result(bro)
real(rp), intent(in) :: rea_part
real(rp), intent(in) :: img_part
type(kom_bro) :: bro
call bro%init(rea_part, img_part)
end function
subroutine kom_bro_init(this, rea_part, img_part)
class(kom_bro), intent(out) :: this
real(rp), intent(in) :: rea_part
real(rp), intent(in) :: img_part
this%dio_rea = rea_part
this%dio_img = img_part
end subroutine
subroutine kom_bro_print(this)
class(kom_bro), intent(in) :: this
print *, this%dio_rea, this%dio_img
end subroutine
function kom_bro_sab(bro_a, bro_b) result(bro_c)
type(kom_bro), intent(in) :: bro_a
type(kom_bro), intent(in) :: bro_b
type(kom_bro) :: bro_c
bro_c%dio_rea = bro_a%dio_rea + bro_b%dio_rea
bro_c%dio_img = bro_a%dio_img + bro_b%dio_img
end function
end module
程序(文件名a.f90
)
program kompleksni_broj
use mod_kompleks
use, intrinsic :: iso_c_binding, only : rp => c_double
implicit none
integer :: i
type(kom_bro) :: broj_01(3), broj_02(3), broj_03(3)
do i = 1, 3
call broj_01(i)%init(i + 2.2_rp, i + 3.3_rp) ! initialization via type-bound routine
broj_02(i) = kom_bro(i + 4.4_rp, i + 5.5_rp) ! initialization via interface kom_bro aka "type constructor"
broj_03(i) = broj_01(i) + broj_02(i)
call broj_03(i)%print()
end do
end program
输出
$ gfortran -g3 -Wall -fcheck=all b.f90 a.f90 && ./a.out
3.2000000000000002 5.4000000000000004 8.6000000000000014
4.2000000000000002 6.4000000000000004 10.600000000000001
5.2000000000000002 7.4000000000000004 12.600000000000001
这是我写的代码,有点乱,但显示了我认为你想要的东西
ian@eris:~/work/stack$ gfortran --version
GNU Fortran (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0
Copyright (C) 2017 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.
ian@eris:~/work/stack$ cat poly.f90
module mod_kompleks
use, intrinsic :: iso_c_binding, only : rp => c_double
implicit none
type, public :: kom_bro
private
real(rp) :: dio_rea
real(rp) :: dio_img
contains
Procedure, private :: kom_bro_sab ! 16 line
Procedure, Public :: print => kom_bro_print
Procedure, Public :: set => kom_bro_set
generic, public :: operator(+) => kom_bro_sab ! 18 line
end type kom_bro
!!$ interface kom_bro
!!$
!!$ module procedure :: kom_bro_set
!!$
!!$ end interface kom_bro
Private
contains
! procedure - kom_bro_set
!!$ type(kom_bro) function kom_bro_set(rea_part, img_part) result(bro_c)
Subroutine kom_bro_set( bro_c, rea_part, img_part)
Class( kom_bro ), Intent( InOut ) :: bro_c
real, intent(in) :: rea_part, img_part
bro_c%dio_rea = rea_part
bro_c%dio_img = img_part
!!$ end function kom_bro_set
end Subroutine kom_bro_set
! procedure - kom_bro_sab
function kom_bro_sab(bro_a, bro_b) result(bro_c)
Class(kom_bro), intent(in) :: bro_a
Class(kom_bro), intent(in) :: bro_b
Class(kom_bro), Allocatable :: bro_c
! Allocate the return value to the same type as
! one of the provided arguments - may have to modify this depending
! on requirements
Allocate( bro_c, Mold = bro_a )
bro_c%dio_rea = bro_a%dio_rea + bro_b%dio_rea
bro_c%dio_img = bro_a%dio_img + bro_b%dio_img
end function kom_bro_sab
Subroutine kom_bro_print( bro_a )
Class( kom_bro ), Intent( In ) :: bro_a
Write( *, * ) 'Real: ', bro_a%dio_rea, ' Imag: ', bro_a%dio_img
End Subroutine kom_bro_print
end module mod_kompleks
program kompleksni_broj
use, non_intrinsic :: mod_kompleks
implicit none
integer :: i
type(kom_bro) :: broj_01(5)
type(kom_bro) :: broj_02(5)
type(kom_bro) :: broj_03(5)
do i = 1, 5
!!$ broj_01(i) = kom_bro(i + 2.2,i + 3.3)
!!$ broj_02(i) = kom_bro(i + 4.4,i + 5.5)
Call broj_01(i)%set(i + 2.2,i + 3.3)
Call broj_02(i)%set(i + 4.4,i + 5.5)
broj_03(i) = broj_01(i) + broj_02(i)
Write( *, * ) i
Call broj_01(i)%print
Write( *, * ) i
Call broj_02(i)%print
Write( *, * ) i
Call broj_03(i)%print
Write( *, * )
end do
end program kompleksni_broj
ian@eris:~/work/stack$ gfortran -std=f2008 -Wall -Wextra -fcheck=all poly.f90
ian@eris:~/work/stack$ ./a.out
1
Real: 3.2000000476837158 Imag: 4.3000001907348633
1
Real: 5.4000000953674316 Imag: 6.5000000000000000
1
Real: 8.6000001430511475 Imag: 10.800000190734863
2
Real: 4.1999998092651367 Imag: 5.3000001907348633
2
Real: 6.4000000953674316 Imag: 7.5000000000000000
2
Real: 10.599999904632568 Imag: 12.800000190734863
3
Real: 5.1999998092651367 Imag: 6.3000001907348633
3
Real: 7.4000000953674316 Imag: 8.5000000000000000
3
Real: 12.599999904632568 Imag: 14.800000190734863
4
Real: 6.1999998092651367 Imag: 7.3000001907348633
4
Real: 8.3999996185302734 Imag: 9.5000000000000000
4
Real: 14.599999427795410 Imag: 16.800000190734863
5
Real: 7.1999998092651367 Imag: 8.3000001907348633
5
Real: 9.3999996185302734 Imag: 10.500000000000000
5
Real: 16.599999427795410 Imag: 18.800000190734863
ian@eris:~/work/stack$
我的 IDE 是:Code::Blocks 20.03 (MinGW 9.2.0)
这是我的简单代码:
module mod_kompleks
use, intrinsic :: iso_c_binding, only : rp => c_double
implicit none
type, public :: kom_bro
private
real(rp) :: dio_rea
real(rp) :: dio_img
contains
procedure, private :: kom_bro_sab ! 16 line
generic, public :: operator(+) => kom_bro_sab ! 18 line
end type kom_bro
interface kom_bro
module procedure :: kom_bro_set
end interface kom_bro
contains
! procedure - kom_bro_set
type(kom_bro) function kom_bro_set(rea_part, img_part) result(bro_c)
real, intent(in) :: rea_part, img_part
bro_c%dio_rea = rea_part
bro_c%dio_img = img_part
end function kom_bro_set
! procedure - kom_bro_sab
function kom_bro_sab(bro_a, bro_b) result(bro_c)
type(kom_bro), intent(in) :: bro_a
type(kom_bro), intent(in) :: bro_b
type(kom_bro) :: bro_c
bro_c%dio_rea = bro_a%dio_rea + bro_b%dio_rea
bro_c%dio_img = bro_a%dio_img + bro_b%dio_img
end function kom_bro_sab
end module mod_kompleks
program kompleksni_broj
use, non_intrinsic :: mod_kompleks
implicit none
integer :: i
type(kom_bro) :: broj_01(3)
type(kom_bro) :: broj_02(3)
type(kom_bro) :: broj_03(3)
do i = 1, 3
broj_01(i) = kom_bro(i + 2.2,i + 3.3)
broj_02(i) = kom_bro(i + 4.4,i + 5.5)
broj_03(i) = broj_01(i) + broj_02(i)
end do
end program kompleksni_broj
我打算定义一个看起来像复数但也允许将两个复数相加的算术运算的用户类型。由于我在示例中没有使用 Fortran 编程语言的经验,因此我遇到了编译器向我报告以下错误的问题:
|16|Error: Non-polymorphic passed-object dummy argument of 'kom_bro_sab'
|18|Error: Undefined specific binding 'kom_bro_sab' as target of GENERIC '+'
||=== Build failed: 2 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|
我对编程语言 Fortran 中的 OOP 的了解不足以让我自己解决这个问题。 甚至可以定义这样的用户定义类型吗?
您有多个错误。最重要的是运算符重载是错误的。请参阅下面我的示例实现。
复数的派生数据类型(文件名b.f90
)
module mod_kompleks
use, intrinsic :: iso_c_binding, only : rp => c_double
implicit none
private
public kom_bro
public operator(+)
type kom_bro
private
real(rp) :: dio_rea
real(rp) :: dio_img
contains
procedure :: init => kom_bro_init
procedure :: print => kom_bro_print
end type
interface operator(+)
module procedure kom_bro_sab
end interface
interface kom_bro
module procedure kom_bro_init2
end interface
contains
function kom_bro_init2(rea_part, img_part) result(bro)
real(rp), intent(in) :: rea_part
real(rp), intent(in) :: img_part
type(kom_bro) :: bro
call bro%init(rea_part, img_part)
end function
subroutine kom_bro_init(this, rea_part, img_part)
class(kom_bro), intent(out) :: this
real(rp), intent(in) :: rea_part
real(rp), intent(in) :: img_part
this%dio_rea = rea_part
this%dio_img = img_part
end subroutine
subroutine kom_bro_print(this)
class(kom_bro), intent(in) :: this
print *, this%dio_rea, this%dio_img
end subroutine
function kom_bro_sab(bro_a, bro_b) result(bro_c)
type(kom_bro), intent(in) :: bro_a
type(kom_bro), intent(in) :: bro_b
type(kom_bro) :: bro_c
bro_c%dio_rea = bro_a%dio_rea + bro_b%dio_rea
bro_c%dio_img = bro_a%dio_img + bro_b%dio_img
end function
end module
程序(文件名a.f90
)
program kompleksni_broj
use mod_kompleks
use, intrinsic :: iso_c_binding, only : rp => c_double
implicit none
integer :: i
type(kom_bro) :: broj_01(3), broj_02(3), broj_03(3)
do i = 1, 3
call broj_01(i)%init(i + 2.2_rp, i + 3.3_rp) ! initialization via type-bound routine
broj_02(i) = kom_bro(i + 4.4_rp, i + 5.5_rp) ! initialization via interface kom_bro aka "type constructor"
broj_03(i) = broj_01(i) + broj_02(i)
call broj_03(i)%print()
end do
end program
输出
$ gfortran -g3 -Wall -fcheck=all b.f90 a.f90 && ./a.out
3.2000000000000002 5.4000000000000004 8.6000000000000014
4.2000000000000002 6.4000000000000004 10.600000000000001
5.2000000000000002 7.4000000000000004 12.600000000000001
这是我写的代码,有点乱,但显示了我认为你想要的东西
ian@eris:~/work/stack$ gfortran --version
GNU Fortran (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0
Copyright (C) 2017 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.
ian@eris:~/work/stack$ cat poly.f90
module mod_kompleks
use, intrinsic :: iso_c_binding, only : rp => c_double
implicit none
type, public :: kom_bro
private
real(rp) :: dio_rea
real(rp) :: dio_img
contains
Procedure, private :: kom_bro_sab ! 16 line
Procedure, Public :: print => kom_bro_print
Procedure, Public :: set => kom_bro_set
generic, public :: operator(+) => kom_bro_sab ! 18 line
end type kom_bro
!!$ interface kom_bro
!!$
!!$ module procedure :: kom_bro_set
!!$
!!$ end interface kom_bro
Private
contains
! procedure - kom_bro_set
!!$ type(kom_bro) function kom_bro_set(rea_part, img_part) result(bro_c)
Subroutine kom_bro_set( bro_c, rea_part, img_part)
Class( kom_bro ), Intent( InOut ) :: bro_c
real, intent(in) :: rea_part, img_part
bro_c%dio_rea = rea_part
bro_c%dio_img = img_part
!!$ end function kom_bro_set
end Subroutine kom_bro_set
! procedure - kom_bro_sab
function kom_bro_sab(bro_a, bro_b) result(bro_c)
Class(kom_bro), intent(in) :: bro_a
Class(kom_bro), intent(in) :: bro_b
Class(kom_bro), Allocatable :: bro_c
! Allocate the return value to the same type as
! one of the provided arguments - may have to modify this depending
! on requirements
Allocate( bro_c, Mold = bro_a )
bro_c%dio_rea = bro_a%dio_rea + bro_b%dio_rea
bro_c%dio_img = bro_a%dio_img + bro_b%dio_img
end function kom_bro_sab
Subroutine kom_bro_print( bro_a )
Class( kom_bro ), Intent( In ) :: bro_a
Write( *, * ) 'Real: ', bro_a%dio_rea, ' Imag: ', bro_a%dio_img
End Subroutine kom_bro_print
end module mod_kompleks
program kompleksni_broj
use, non_intrinsic :: mod_kompleks
implicit none
integer :: i
type(kom_bro) :: broj_01(5)
type(kom_bro) :: broj_02(5)
type(kom_bro) :: broj_03(5)
do i = 1, 5
!!$ broj_01(i) = kom_bro(i + 2.2,i + 3.3)
!!$ broj_02(i) = kom_bro(i + 4.4,i + 5.5)
Call broj_01(i)%set(i + 2.2,i + 3.3)
Call broj_02(i)%set(i + 4.4,i + 5.5)
broj_03(i) = broj_01(i) + broj_02(i)
Write( *, * ) i
Call broj_01(i)%print
Write( *, * ) i
Call broj_02(i)%print
Write( *, * ) i
Call broj_03(i)%print
Write( *, * )
end do
end program kompleksni_broj
ian@eris:~/work/stack$ gfortran -std=f2008 -Wall -Wextra -fcheck=all poly.f90
ian@eris:~/work/stack$ ./a.out
1
Real: 3.2000000476837158 Imag: 4.3000001907348633
1
Real: 5.4000000953674316 Imag: 6.5000000000000000
1
Real: 8.6000001430511475 Imag: 10.800000190734863
2
Real: 4.1999998092651367 Imag: 5.3000001907348633
2
Real: 6.4000000953674316 Imag: 7.5000000000000000
2
Real: 10.599999904632568 Imag: 12.800000190734863
3
Real: 5.1999998092651367 Imag: 6.3000001907348633
3
Real: 7.4000000953674316 Imag: 8.5000000000000000
3
Real: 12.599999904632568 Imag: 14.800000190734863
4
Real: 6.1999998092651367 Imag: 7.3000001907348633
4
Real: 8.3999996185302734 Imag: 9.5000000000000000
4
Real: 14.599999427795410 Imag: 16.800000190734863
5
Real: 7.1999998092651367 Imag: 8.3000001907348633
5
Real: 9.3999996185302734 Imag: 10.500000000000000
5
Real: 16.599999427795410 Imag: 18.800000190734863
ian@eris:~/work/stack$