【问题标题】:Reason of extra flexibility when using fortran intrinsics使用 fortran 内在函数时具有额外灵活性的原因
【发布时间】:2020-05-25 05:41:48
【问题描述】:

假设我在 fortran 中使用实变量定义了一个函数 f(x)=x**2,并且我定义了两个数组 x(100) 和 y(100),其中 x(i)=real(i),比如说.

现在,要加载数组 y(100) 中函数的所有值,如果我使用内在函数(比如 sin),我只需编写

y=sin(x)

但是,要加载 f(x),我必须写

do i=1,100
y(i)=f(x(i))
enddo

如果我使用

y=f(x)

它会给出一个标量向量秩不匹配错误。 我应该以什么方式定义函数,以便它也可以像 sin 内在函数一样使用?

此外,在固有的 sin 中,我可以使用 real 和 complex 作为参数,但不能在用户定义的函数中完成,并且会给出类型不匹配错误(real complex)。 内在函数具有额外灵活性的原因是什么?如何定义我自己的函数来模仿内在函数?

【问题讨论】:

  • 你应该学习基本程序。大多数内在函数都是基本的,您可以声明自己的。
  • 对于问题的第二部分,您可以编写多个函数,它们的参数类型、种类或等级不同,然后是定义通用名称的接口。然后您可以通过通用名称调用,编译器将通过参数进行区分,调用特定的函数。参见,例如,stackoverflow.com/questions/2257248/…
  • 投票重新打开,因为给定的副本没有回答整个问题
  • @IanBush 问题的哪一部分?通用功能和元素吸力都在那里进行了处理。我们至少应该在此处保留链接stackoverflow.com/questions/16786965/… 另外,为什么不只是另一个更多关于泛型的重复目标?
  • 我可以看到如何处理不同的等级,但不是不同的数据类型 - 是的,泛型涵盖了它,但我阅读链接问题的答案的方式是它们纯粹关注多等级大小写,而不是不同的数据类型

标签: function fortran


【解决方案1】:

在不同级别工作

TLDR: 如果可能的话,如果您将所有过程声明为pureelemental,您将大大改进您的代码。 通过这样做,您可以自动获得内部函数的大部分行为。

如果没有副作用,一个过程(函数或子例程)可以是pure。 函数有额外的约束,它可能没有 outinout 参数。

如果您有一个仅作用于标量值的pure 过程,您可以将其声明为elemental。这将向编译器发出信号,表明对数组的一个元素执行此过程完全独立于对其他数组元素的执行。 这将允许您使用与内在函数相同的语法糖。请注意,elemental 过程甚至可以有多个参数。 一些编译器甚至会使用elemental 信息来自动并行执行。

一个例子:

! implicit none is assumed
real elemental function double_pow(x, n)
    real, intent(in) :: x
    integer, intent(in) :: n
    double_pow = x**(2 * n)
end function

double_pow(2., 2) == 2.**(2 * 2)
double_pow([1. 2.], 2) == [1.**(2 * 2), 2.**(2 * 2)]
! in the last case, the arrays have to have the same shape
double_pow([1. 2.], [1, 2]) == [1.**(1 * 2), 2.**(2 * 2)]

注 1: 基本过程和内在过程之间仍然存在很大差异。 即使是基本函数也不能用于初始化parameter 变量(编译时常量。)

! possible
real, parameter :: PI = atan(1.0) * 4.0
! not possible
real, parameter :: four = double_pow(2.0, 1)

注2: 在pure 过程中允许使用一些具有副作用的语句(例如error stop)。 此外,pure subroutines 可能有 inout 参数,因此它们在计算机科学意义上并不完全是纯粹的。

处理不同的数据类型

您必须为作用于不同数据类型的两个不同函数创建一个通用接口。 正如 cmets 中所述,该问题已有多个答案:

只是一个简短的例子

module test_mod
    implicit none(type, external)
    private
    public :: double

    interface double
        module procedure double_real, double_integer
    end interface

contains
    real pure function double_real(x)
        real, intent(in) :: x
        double_real = 2.0 * x
    end function

    integer elemental function double_integer(x)
        integer, intent(in) :: x
        double_integer = 2 * x
    end function
end module

【讨论】:

    猜你喜欢
    • 2021-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-17
    • 2022-01-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多