Fortran中数学函数的前缀(D、C、Q 等):加还是不加?

学术   教育   2024-10-18 22:17   山东  

在编程的世界里,Fortran 以其高效性和稳定性在科学计算领域占据了重要的位置。尤其在处理复杂的数学运算时,Fortran 提供了一系列内置的数学函数,以满足不同精度需求的计算。然而,随着计算需求的多样化,简单的数学函数已经不能完全满足用户的需求。为此,Fortran 在其标准中引入了带有特定前缀的数学函数,如 dsincsin 等,这些前缀分别代表了不同的计算精度和数据类型。本文将详细介绍这些前缀的意义及其使用方法,帮助 Fortran 程序员更好地理解和应用这些函数。

数学函数前缀的意义

在 Fortran 中,数学函数前缀主要用于指定函数的计算精度和处理的数据类型。常见的前缀包括:

  • 「D」:表示双精度(Double Precision),通常用于 real(kind=8) 类型的数据。

  • 「C」:表示复数(Complex),用于处理复数类型的计算。

  • 「Q」:表示四精度(Quadruple Precision),通常用于 real(kind=16) 类型的数据,但并不是所有编译器都支持。

  • 「B」:表示超短整型(Byte),用于 integer(kind=1) 类型的数据。

  • 「II」:表示短整型(Short Integer),用于 integer(kind=2) 类型的数据。

  • 「I」:表示整型(Integer),用于 integer(kind=4) 类型的数据。

  • 「KI」:表示长整型(Long Integer),用于 integer(kind=8) 类型的数据。

例如,dsin 表示双精度的正弦函数,csin 表示复数的正弦函数,qsin 表示四精度的正弦函数。

通用名与专有名

从 Fortran 90 开始,引入了通用名(「Generic Name」)的概念。通用名允许程序员通过一个统一的名称调用多个具有相似功能但不同实现的函数。编译器会根据传入参数的类型自动选择合适的专有名(「Specific Name」)进行计算。例如,sin 是一个通用名,它可以调用 sindsinqsincsincdsincqsin 等多个专有名。

这种机制极大地简化了代码的编写和维护。程序员只需记住通用名,而无需关心具体的实现细节。例如,以下代码片段展示了如何使用通用名 sin

program main
  implicit none
  real(kind=4) :: x1 = 1.0
  real(kind=8) :: x2 = 1.0D0
  complex(kind=8) :: x3 = (1.0D01.0D0)

  print *, sin(x1)  ! 调用 sin
  print *, sin(x2)  ! 调用 dsin
  print *, sin(x3)  ! 调用 csin
end program main

编译并运行,得到

0.841470957    
0.84147098480789650     
(1.2984575814159773,0.63496391478473613)

在这个例子中,sin 根据传入参数的类型自动选择了合适的专有名进行计算。

另外,使用通用名还有一个重要的好处:对于不带前缀的数学函数,在将来修改数据精度或类型时,工作量会小很多。例如:

program main
  implicit none
  integer , parameter :: DP = 8 !// 将来只修改此处,如 DP = 16
  realkind = DP ) :: r = -1.0_DP
  write( * , * ) acos(r) , atan(r) , asin(r)
  !write( * , * ) dacos(r) , datan(r) , dasin(r)
end program main

如果上面的代码使用了带前缀的函数,将来想要将双精度改为四精度,则需同时修改多个函数名,比如 dacos 修改为 qacosatan 修改为 qatan,这是我们不想看到的。

因此,为方便起见,我们在书写代码时,通常可以不使用任何函数前缀。

何时需要使用专有名

凡事无绝对。尽管通用名提供了极大的便利,但在某些情况下,使用专有名仍然是必要的。主要场景包括:


多个专有名对应相同的输入类型


某些函数可能有多个专有名对应相同的输入类型,但返回不同类型的结果。例如,int 函数可以将实数转换为不同类型的整数。在这种情况下,编译器无法自动选择合适的专有名,程序员需要显式指定。例如:

program main
  implicit none
  real(kind=8) :: x = 1.0D0

  print *, idint(x)  ! 返回 integer(kind=4)
  print *, kidint(x) ! 返回 integer(kind=8)

end program main

注:经测试,gfortran 编译器不支持 kidint,Intel 编译器正常执行。


特殊的精度要求


在某些科学计算中,个别中间变量可能需要非常高的精度。这时,使用四精度(Quadruple Precision)的专有名是必要的。

program main
  implicit none
  real(kind=8) :: x = 1.0D0
  real(kind=16) :: y

  ! 使用通用名 sin,编译器自动选择 qsin
  y = sin(x)
  ! 直接使用专有名 qsin,确保使用四精度计算
  y = qsin(real(x,kind=16))
end program main

在这个例子中,x 是一个双精度实数。使用 sin(x) 时,编译器会选择 qsin 进行计算。为了确保使用四精度计算,我们可以直接使用专有名 qsin

小结

Fortran 的数学函数前缀提供了一种灵活的方式来指定计算的精度和数据类型。通用名和专有名机制使得代码更加简洁和易于维护。在大多数情况下,使用通用名就足够了,编译器会根据参数类型自动选择合适的专有名。然而,在某些特殊情况下,显式使用专有名可以提供更多的控制和灵活性。通过本文的介绍,希望大家能够更好地理解和应用这些数学函数前缀,提高代码的效率和可读性。

推荐阅读

FEtch 系统是笔者团队开发的新一代有限元软件开发平台。只需按照有限元语言格式填写脚本文件,即可在线自动生成基于现代 Fortran 的有限元计算程序,从而大幅提高 CAE 软件的开发效率。欢迎私信交流。

有任何疑问或建议,欢迎加Q群 "FEtch有限元开发系统(519166061)" 留言讨论。我们长期开展 FEtch 系统的试用活动,感兴趣的朋友入群后可直接联系管理员,免费获取许可证文件

有限元语言与编程
面向科学计算,探索CAE,有限元,数值分析,高性能计算,数据可视化,以及 Fortran、C/C++、Python、Matlab、Mathematica 等语言编程。这里提供相关的技术文档和咨询服务,不定期分享学习心得。Enjoy!
 最新文章