首页 > 解决方案 > 使 SUM 函数与派生类型一起使用

问题描述

我有一个用户类型,其中包含两个或多个不同大小的数组。

type state    
    real(real64) :: pos(3), ori(4), vee(3), omg(3)
end type

我已经定义了(*)and(+)运算符以便能够做代数

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吗?还是我需要其他定义?

我正在使用 Intel® Fortran Compiler Classic 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%)。它必须是函数结果的所有数组复制值。身份证。

标签: fortran

解决方案


用户定义的泛型特定过程operator(+)不(也不应该)暗示sum. 如果您希望为仿制药提供一个特定的程序,sum那么您必须自己提供一个。

在 Fortran 中,内在的sum(对于内在的数字类型)没有定义,+因此派生类型没有自然的类似物。

同样,productand也不是根据andnorm2来定义的。*+

这个问题似乎喜欢dot_product. 虽然这个函数*根据(and )定义的,sum但这并没有用:内在函数只接受内在类型并且不考虑sumand的特定过程operator(*)


推荐阅读