首页 > 教程 > 正文

阅读排行

为什么要在数学函数前面加D,加C加Q?如dsin
2014-06-16 12:44:28   来源:Fcode研讨团队   评论:0 点击:

本文描述了数学函数前增加 D,C,Q 前缀的原因,分析了加前缀与不加前缀的区别。得出结论为:在大多数时候,无需使用前缀。

第一. 数学函数加前缀的含义

相信很多学友都知道,加 D 的含义是,使得计算变为双精度计算。比如 dsin 为双精度的正弦函数,dacos 为双精度的反余弦函数。

而加 C ,可以使得计算变为复数计算。比如 cabs 为复数求绝对值(求模),而 csqrt 为复数开方。等等。

类似的还有:
C 使计算变为复数计算
D 使计算变为双精度计算(Kind=8)
Q 使计算变为四精度计算(Kind=16)(部分编译器)
B 使计算变为超短整型计算(Kind=1)
II 使计算变为短整型计算(Kind=2)
I 使计算变为整型计算(Kind=4)
KI 使计算变为长整型计算(Kind=8)

另外,C 前缀,可以与 D, Q 前缀组合,比如 CDABS 为双精度复数求模,CQSQRT 为四精度复数开方。

第二.  关于 Generic Name 和 Specific Name

从F90以后,语法新增了 Generic Name 的用法。(详询彭国伦《Fortran95程序设计》323页,第11-3-1节,但叫法不同)

多个接口类似,功能相似的函数。可以捆绑在一起,形成一个通用的名字(Generic Name),此时他们原来的名字称为专有名(Specific Name)。在调用这些函数时,可以直接调用这个通用名(Generic Name),编译器实质上调用的,是根据参数的个数、类型、顺序自动选择匹配的专有名字(Specific Name)函数。

如上例,sin , dsin , qsin , csin , cdsin , cqsin 专有名(Specific Name),他们共同捆绑成一个 sin通用名(Generic Name)。

当代码中书写  y = sin( x ) 的时候,是调用的通用名,而此时,编译器会根据 x 的类型,自动匹配,使得实际上调用的是 sin , dsin , qsin , csin , cdsin , cqsin 这些专有名中的其中一个。

当然,程序员也可以手动调用他们的专有名函数,比如 y = dsin( x ),此时,不管 x 是什么类型,都会被强制转换为专有名函数要求的类型。

两点需要注意:
1.  sin 本身是通用名,同时 sin 可能也是 sin 通用名下捆绑的专有名。用于 real(kind=4) 的情况。对于 sin 来说,通用名sin和其中一个专有名sin是同名的。这样,程序员就不能单独调用专有名sin了。
但是其他一些 函数,比如 log通用名,它所有的专有名分别是 alog , dlog , qlog , clog , cdlog , cqlog ,而没有 log的专有名。
2.  不同的编译器,可能拥有不同的专有名。而通用名则是所有编译器都具有的。例如 IVF 的 sin 拥有 qsin 这个专有名,用于 real(kind=16) 的情况。但其他编译器不一定拥有。

第三.  加前缀(调用专有名)是否有必要?

答案是否定的。在绝大多数时候,我们不需要增加任何前缀。而可以直接调用通用名。

编译器会根据参数的类型,自动选择合适的函数来进行计算。比如 sin( 1.0D0 ),虽然没有前缀 d,但由于参数 1.0D0 是双精度的,所以编译器实际上也会使用 dsin 来计算,并获得双精度的精度。

因此,我们建议。在书写代码时,一律只书写函数名(不带任何前缀),比如 sin , cos , tan , sqrt , abs 等。让编译器根据参数类型自动适应函数(编译器自动选择专有名)

只有在极少数的情况下,我们才有特意使用专有名的必要。比如:
1. 多个专有名对应同样的输入类型。比如:int( x ) ,当 x 的类型时 real(kind=8) 的时候,依然对应有多个专有名:
iidint , idint , kidint 分别返回 integer(kind=2 , 4 , 8 ) 
此时,编译器无法知道我们想要返回哪一种?此时,就有必要使用专有名。

2.想要的返回值和输入参数的类型不一样。我们就是想输入双精度,得到单精度。此时,我们也应该使用对应的专有名。

第四. 验证通用名自适应选择专业名函数

其实不需要验证,语法就是如此规定的。在此,我们使用一小段代码来验证。
 

Program www_fcode_cn
  Implicit None
  write( * , * ) acos(-1.0D0) , acos(-1.0) , dacos(-1.0D0)
End Program www_fcode_cn

程序运行后结果为:
3.1415926535897931        3.14159274       3.1415926535897931
可见,第一个 PI 与第三个 PI 一模一样,acos 函数自动根据双精度参数适应为 dacos 函数。默认输出16位,也说明结果是双精度的结果。
而第二个 acos 参数为单精度,因此默认输出为 8 位。表示结果也是单精度。

第五. 为什么不提倡加前缀?

我们建议,在书写代码时,不使用任何前缀。
原因主要有两个: 
1.前缀麻烦,需要书写时额外考虑应该用什么前缀。影响代码书写速度。
2.带前缀的函数,将来修改数据精度或类型时,修盖量巨大。
Program www_fcode_cn
  Implicit None
  Integer , parameter :: DP = 8 !// 将来只修改此处,如 DP = 16
  Real( Kind = DP ) :: r = -1.0_DP
  write( * , * ) acos(r) , atan(r) , asin(r)
  !// 如果写为下面的方式,则还需修改三个函数名,比如 dacos 修改为 qacos
  !write( * , * ) dacos(r) , datan(r) , dasin(r)
End Program www_fcode_cn

相关热词搜索:函数 数学 双精度

上一篇:关于 encompassing scoping unit Error 错误
下一篇:新语法系列之 强大的 Fortran 2003

分享到: 收藏