问题 正确使用PURE关键字Fortran


我正在钻研Fortran而且我遇到了 pure 关键字指定没有副作用的函数/子例程。

我有一本书, Fortran 90/95 由S Chapman介绍 pure 关键字,但奇怪的是没有提供“良好的编码实践”使用。

我想知道如何在程序中使用这个关键字。只是环顾四周,对我来说很明显,大多数没有副作用的程序都没有必要包括 pure 关键词。

那么它最好用在哪里?只有在想要的程序中 全然 保证没有副作用?或者也许在计划转换为的程序中 elemental 程序以后? (如 elemental 程序必须首先 pure。)


1111
2018-05-15 16:46


起源

好吧,我试着用 pure 尽可能多地开展工作。它迫使我编写干净的代码。然而,只有一小部分例程实际上可以是纯粹的...但我从未在速度等方面看到过任何差异。 - Alexander Vogt
这不是Fortran 90/95但请注意 elemental 程序可以 impure。 - francescalus
@AlexanderVogt“只有一小部分”?在我看来,大多数函数/子程序都是 pure 正确编码时。据我所知,我的书中只有修改变量的程序 intent(in) 或者I / O组件不会 pure。对我来说,这似乎是少数,而不是多数。 - River
可悲的是,没有......一旦I / O进场,这就不可能了。指针吗?不纯。 C绑定?有些内在函数是纯粹的,有些则不是。甚至一些内在函数对于一些编译器(版本)也是不纯的......只要一个例程不纯,所有调用例程都是不纯的:( - Alexander Vogt
尽管如此,许多小程序仍然可以轻松地避免使用指针或I / O,具体取决于正在编写的程序类型。你是说那个 pure 应尽可能使用关键字?这看起来似乎不是基于我查看过的Fortran代码的标准使用方法。 - River


答案:


PURE 在某些情况下是必需的 - 例如,在规范表达式中调用的过程或来自 FORALL 要么 DO CONCURRENT 结构体。 PURE 在这些情况下,要求Fortran处理器在过程调用的顺序上具有灵活性,同时仍然具有来自特定代码段的合理确定性结果。

除了那些必要的案例,是否使用 PURE 或不是基本上是一种风格问题,这在某种程度上是主观的。

使用成本 PURE (无法在程序中执行IO,无法调用不可执行的程序 PURE)和好处(今天编写的纯程序可以从明天编写的上下文中调用,需要一个纯粹的过程,因为 PURE 程序没有副作用调用这种程序的含义可能对代码的读者更清楚),两者之间的权衡取决于具体情况。

该标准可能为Fortran处理器提供了相当大的方法,可用于评估表达式中的表达式和函数引用。它肯定会在某些方面限制程序围绕函数执行的副作用和函数参数的修改。对纯函数的要求与那些约束和那些约束一致,因此有些人使用大多数函数都是纯粹的样式。同样,它可能仍然取决于具体情况,并且可能必须存在例外情况,例如C互操作性或与外部API的交互。


8
2018-05-19 01:35



其他答案提出了有关使用的其他有用信息 pure 应该更多地了解如何 pure 让编译器通过无序并行化进行优化。 - River
@IanH如果我定义一个纯函数 f 并在表达式中使用它 x=f(a*b)+f(a*b)那就是这样的 f 总是被叫一次?似乎测试是否真的不可能,因为这需要在函数中加入某种副作用。 - Raul Laasner
@RaulLaasner号 f 可能被称为零,一次或两次,这与是否无关 f 很纯洁。 - IanH
你可以通过简单地制作一个运行很长时间的纯函数来测试它。基于这样一个测试的总计,intel fortran显然没有优化 f(arg)+f(arg) 至 2*f(arg), 有还是没有 pure 宣言。 - agentp


正如chw21所建议的,主要动机是 PURE 是让编译器更好地优化。特别是缺乏 PURE 对于函数,将防止由于未知副作用导致的并行化。注意 PURE 与函数不同,子程序可能有 INTENT(INOUT) 争论,但仍有副作用的限制(和a PURE 程序只能打电话给其他人 PURE 程序。)

通过Fortran 2003, ELEMENTAL 程序是隐含的 PURE。 Fortran 2008增加了一个 IMPURE 可以使用的前缀 ELEMENTAL 禁用该方面的过程。


5
2018-05-16 14:22



你有任何基准可用吗? pure 语句实际上会导致编译器更好的优化?我只是很好奇,我过去曾尝试过这种做法,但看不出任何好处 gfortran 要么 ifort。 - Alexander Vogt
如果我把 PURE 关于非纯函数的关键字,编译器会抛出错误。很明显,编译器可以自己做出这个决定,因此人们可能会期望它能够做到这一点,从而优化代码。 - agentp
这些答案有助于我更好地理解其中的好处 pure 关键字,但我仍然更喜欢它的常用方法。是应该尽可能使用它还是更类似于小工具,多线程和其他只在速度非常重要的情况下才常见的事情? - River
@agentp假设编译器在编译对过程的引用时可以“看到”标记为PURE的过程的主体。情况并非总是如此 - 考虑单独编译外部或单独模块程序的可能性。 - IanH


如果您尝试更改具有的变量 INTENT(IN),它不会编译。

纯粹的功能只能有 INTENT(IN) 参数,并返回仅依赖于参数的值。纯子程序可以修改 INTENT(OUT) 和 INTENT(INOUT) 参数,但同样,仅基于参数的值。

在这两种情况下:相同的参数 - >相同的结果。

优点是它保证编译器可以在不改变程序行为的情况下交换执行顺序(以优化代码)。


0
2018-05-16 11:16



“纯粹的功能只能有 INTENT(IN) 参数“:not true:指针或过程的伪参数不需要指定。 - francescalus
我刚刚尝试过,你是对的:一个纯函数可以有一个非INTENT(IN) 指针伪参数。而英特尔fortran编译器甚至允许你改变它的价值! gfortran 给出编译时错误。 - chw21
如果通过“更改其值”表示指针的目标值,则gfortran会出现错误。指针伪参数的INTENT用于指针的关联状态,而不是它指向的状态。见F2008,第5.3.10节,第2段。 - Steve Lionel
纯函数(或纯子例程中的intent(out)参数的值)的结果可能取决于参数以外的其他东西 - 例如,它们可以依赖于use或host关联变量。纯程序不能做的是修改程序的状态而不是通过其参数或函数结果。如果在适当的上下文中调用纯过程,则这是允许重新排序执行纯过程的特性。 - IanH
@IanH我发现你的评论对澄清这个答案的含义非常有用。如果您可以编辑包含它的答案,我认为它会有所帮助(并使这个答案更好)。 - River