使 SUM 函数与派生类型一起工作
Making SUM function work with derived types
我有一个用户类型,其中包含两个或多个不同大小的数组。
type state
real(real64) :: pos(3), ori(4), vee(3), omg(3)
end type
并且我定义了 (*)
和 (+)
运算符以便能够进行代数计算
interface operator (+)
procedure st_add
end interface
interface operator (*)
procedure st_scale1, st_scale2
end interface
contains
elemental function st_add(a,b) result(c)
type(state), intent(in) :: a,b
type(state) :: c
c = state( &
a%pos + b%pos, &
a%ori + b%ori, &
a%vee + b%vee, &
a%omg + b%omg)
end function
elemental function st_scale1(a,b) result(c)
real(real64), intent(in) :: a
type(state), intent(in) :: b
type(state) :: c
c = state( &
a * b%pos, &
a * b%ori, &
a * b%vee, &
a * b%omg)
end function
elemental function st_scale2(b,a) result(c)
real(real64), intent(in) :: a
type(state), intent(in) :: b
type(state) :: c
c = state( &
a * b%pos, &
a * b%ori, &
a * b%vee, &
a * b%omg)
end function
现在我在线性代数运算中使用上述内容,例如
real(real64), parameter :: c(4) = [1/6d0, 2/6d0, 2/6d0, 1/6d0]
type(state) :: k(4),k_step
k_step = c(1)*k(1)+c(2)*k(2)+c(3)*k(3)+c(4)*k(4)
但为了简洁和代码的灵活性,我想要使用以下内容
k_step = sum( c(:)*k(:) ) ! error
导致以下错误 error #6362: The data types of the argument(s) are invalid. [SUM]
.
那么我有什么选择呢? sum
调用 st_add
是否需要通用接口?或者我需要一些其他定义吗?
我正在使用英特尔® Fortran 经典编译器 2021.1.2(oneAPI HPC 的一部分)。
解决方案
最有效的解决方案是添加以下内容
interface sum
procedure st_sum
end interface
contains
pure function st_sum(a) result (s)
type(state), intent(in) :: a(:)
type(state) :: s
integer :: i, n
n = size(a)
s = a(1)
do i=2, n
s = s + a(i)
end do
end function
和用法
k_step = sum(c(:)*k(:))
st = this + h*k_step
嗯,其实我把上面的两种说法合二为一了
st = this + sum( (h*c(:))*k(:) )
总的来说,我得到了相同的结果,但有轻微的性能损失(大约 10%)。它必须是函数结果的所有数组复制值。 IDK.
我需要一个通用接口来求和st_add吗?
您确实需要向 sum
通用接口添加特定功能。该函数在内部调用什么并不重要。它必须是适用于 state
类型数组的函数,这很重要。
interface sum
procedure your_function
end interface
function your_function(a)
type(state) :: your_function
type(state), intent(in) :: a(:)
...
end function
通用 operator(+)
的用户定义特定过程不(也不应该)暗示 sum
的实现。如果您希望为通用 sum
提供特定程序,那么您必须自己提供一个。
在 Fortran 中,内部 sum
(对于内部数字类型)不是根据 +
定义的,因此派生类型没有自然的类似物。
同样,product
和 norm2
不是根据 *
和 +
定义的。
题主似乎喜欢dot_product
的想法。尽管此函数 是 根据 *
(和 sum
)定义的,但这没有用:内部函数仅采用内部类型并且不考虑特定sum
和 operator(*)
.
的程序
我有一个用户类型,其中包含两个或多个不同大小的数组。
type state
real(real64) :: pos(3), ori(4), vee(3), omg(3)
end type
并且我定义了 (*)
和 (+)
运算符以便能够进行代数计算
interface operator (+)
procedure st_add
end interface
interface operator (*)
procedure st_scale1, st_scale2
end interface
contains
elemental function st_add(a,b) result(c)
type(state), intent(in) :: a,b
type(state) :: c
c = state( &
a%pos + b%pos, &
a%ori + b%ori, &
a%vee + b%vee, &
a%omg + b%omg)
end function
elemental function st_scale1(a,b) result(c)
real(real64), intent(in) :: a
type(state), intent(in) :: b
type(state) :: c
c = state( &
a * b%pos, &
a * b%ori, &
a * b%vee, &
a * b%omg)
end function
elemental function st_scale2(b,a) result(c)
real(real64), intent(in) :: a
type(state), intent(in) :: b
type(state) :: c
c = state( &
a * b%pos, &
a * b%ori, &
a * b%vee, &
a * b%omg)
end function
现在我在线性代数运算中使用上述内容,例如
real(real64), parameter :: c(4) = [1/6d0, 2/6d0, 2/6d0, 1/6d0]
type(state) :: k(4),k_step
k_step = c(1)*k(1)+c(2)*k(2)+c(3)*k(3)+c(4)*k(4)
但为了简洁和代码的灵活性,我想要使用以下内容
k_step = sum( c(:)*k(:) ) ! error
导致以下错误 error #6362: The data types of the argument(s) are invalid. [SUM]
.
那么我有什么选择呢? sum
调用 st_add
是否需要通用接口?或者我需要一些其他定义吗?
我正在使用英特尔® Fortran 经典编译器 2021.1.2(oneAPI HPC 的一部分)。
解决方案
最有效的解决方案是添加以下内容
interface sum
procedure st_sum
end interface
contains
pure function st_sum(a) result (s)
type(state), intent(in) :: a(:)
type(state) :: s
integer :: i, n
n = size(a)
s = a(1)
do i=2, n
s = s + a(i)
end do
end function
和用法
k_step = sum(c(:)*k(:))
st = this + h*k_step
嗯,其实我把上面的两种说法合二为一了
st = this + sum( (h*c(:))*k(:) )
总的来说,我得到了相同的结果,但有轻微的性能损失(大约 10%)。它必须是函数结果的所有数组复制值。 IDK.
我需要一个通用接口来求和st_add吗?
您确实需要向 sum
通用接口添加特定功能。该函数在内部调用什么并不重要。它必须是适用于 state
类型数组的函数,这很重要。
interface sum
procedure your_function
end interface
function your_function(a)
type(state) :: your_function
type(state), intent(in) :: a(:)
...
end function
通用 operator(+)
的用户定义特定过程不(也不应该)暗示 sum
的实现。如果您希望为通用 sum
提供特定程序,那么您必须自己提供一个。
在 Fortran 中,内部 sum
(对于内部数字类型)不是根据 +
定义的,因此派生类型没有自然的类似物。
同样,product
和 norm2
不是根据 *
和 +
定义的。
题主似乎喜欢dot_product
的想法。尽管此函数 是 根据 *
(和 sum
)定义的,但这没有用:内部函数仅采用内部类型并且不考虑特定sum
和 operator(*)
.