预计阅读本页时间:-
在历史上,FORTRAN是进行数学科学计算和工程计算的首选语言。C90使C的计算方法更加接近于FORTRAN。例如,float.h中使用的浮点数说明规范就是基于FORTRAN标准委员会开发的模型的。C99标准继续进行了增强C的计算能力的工作。
B.8.1 IEC浮点数标准
IEC(International Electotechnical Committee,国际电工委员会)已经发布了浮点数计算的标准(IEC 60559)。这个标准包括了关于浮点数格式、精度、NaN、无穷值、舍入惯例、转换、异常以及推荐的函数和算法等等的讨论。C99接受了这个标准,把它作为C中实现浮点数计算的指导方针。C99中增加的大多数浮点数工具(例如fenv.h头文件和一些新的数学函数)都是这种努力的结果。
广告:个人专属 VPN,独立 IP,无限流量,多机房切换,还可以屏蔽广告和恶意软件,每月最低仅 5 美元
但是有的实现可能不满足IEC 60559中的所有要求;例如,可能底层的硬件无法完成这些任务。因此C99定义了两个可以用作预处理器指令的宏来进行检查。首先,如果实现符合IEC 60559的浮点数规范,下面的宏:
就根据条件被定义为常量1。其次,如果实现支持IEC 60559的可兼容复数计算,那么宏:
就根据条件被定义为常量1。
如果一个实现中并没有定义这些宏,那就不能保证符合IEC60559。
B.8.2 fenv.h头文件
fenv.h头文件提供了一种与浮点数环境进行交互的方式。也就是说,它允许您设置管理浮点数如何执行计算的浮点数控制模式值(control mode value);也允许您确定浮点数状态标志(status flag)或异常(exception)的值,这些值可以报告有关数学计算效果的信息。举个例子来说,控制模式设置可以指定进行舍入的方法,而如果操作产生了浮点数溢出的话就设置一个状态标志。一个设置状态标志的操作被描述为抛出一个异常。
状态标志和控制模式只有在得到硬件支持时才有意义。例如,如果硬件没有相应的选项,那么就不能改变舍入方法。
可以使用预处理器指令来开启支持:
在程序到达包含该编译指示的代码块的结尾处之前该支持一直有效,或者如果该编译指示是外部的,那么就要到该文件或单元的结尾处。或者也可以使用以下的指令来关闭支持:
也可以使用以下的编译指示:
它恢复编译器的默认状态,这是依赖于实现的。
如果涉及到关键的浮点数计算,这个工具就是重要的。但是一般用户对它的兴趣有限,所以在本附录中不对它进行深入讨论。
B.8.3 STDC FP_CONTRACT编译指示
某些浮点数处理器可以把多运算符的浮点表达式合并为一个单独的运算。例如,处理器可能在一步之内就求出以下表达式的值:
这提高了计算速度,但是它会降低计算的可预测性。STDC FP_CONTRACT允许您开启或关闭这个特性。默认的状态依赖于实现。
要对一个特定的计算关闭这一特性,之后再次开启它,可以这样来做:
B.8.4 对math.h库的增补
C90数学库中的大部分都声明了具有double类型的参数和double类型的返回值的函数,例如:
C99库为所有这些函数都提供了类型为float和long double的版本。这些函数在名称中使用f或1后缀,如下所示:
具有不同精度的函数系列使您可以针对特定的用途来选择所需的最有效的类型和函数。C99也添加了一些通常用在科学、工程和数学计算中的函数。表B.15列出了所有这些函数的类型为double的版本。在很多情况下,这些函数的返回值都可以使用现有的函数来计算得出,但是新的函数可以更快或更准确。例如,log1p(x)表示的值与log(1+x)相同,但是log1p(x)使用了一种不同的算法,对于较小的x值来说它会更加精确。所以您可以使用log()函数进行通常的计算,但是如果精度很关键而且x的值较小,就可以使用log1p()函数。
除了这些函数,数学库还定义了一些与对数值进行分类和舍入有关的常量和函数。例如一个值可以被归类为无穷、不是数(NaN)、正常、低于正常和真0(NaN是一个特别的值,用来表示一个值不是一个数,例如asin(2.0)就返回NaN,因为asin()的参数被定义为是-1到1范围内的值。一个低于正常的数是那些其大小比使用全部精度所能表示的最小值还要小的数)。还有一些专用的比较函数,当一个或多个参数是非正常值时函数的行为与标准的关系运算符不同。
可以使用C99的分类方案来检测计算中的无规律性。例如,对于来自math.h的isnormal()宏,如果它的参数是一个正常的数字,它就返回真。当一个数字变得不正常的时候,如下代码通过该函数结束:
简单地说,有一些扩展支持对如何处理浮点数计算的详细控制。
B.8.5 对复数的支持
复数(complex number)具有一个实部和一个虚部。实部就是普通的实数,例如用浮点数类型表示的数。虚部表示一个虚数。虚数是-1的平方根的倍数。在数学中,复数通常写为类似4.2+2.0i的形式,其中i象征性地表示-1的平方根。
C99支持三种复数类型:
存储类型为float_Complex的值时使用的内存布局与具有两个元素的float数组相同,实部的值存储在第一个元素中,而虚部的值存储在第二个元素中。
C99的实现也支持三种虚数类型:
包含了complex.h头文件,就可以使用complex代替_Complex,使用imaginary代替_Imaginary。为复数类型定义的数学运算遵循一般的数学规则。例如(a+b*I) *(c+d*I)的值就等于(a*c-b*d) +(b*c+a*d) *I。
complex.h头文件定义一些宏和一些接受复数参数并返回复数的函数。特别地,宏I表示-1的平方根。它使您可以进行以下工作:
complex.h头文件提供了一些复数函数的原型,很多都对应于math.h中的函数并使用c前缀。例如csin()函数返回它的复数参数的复正弦。其他的函数与特定的复数特性相关。例如,creal()函数返回一个复数的实部,cimag()函数返回复数的虚部。也就是说,给定一个类型为double complex的z,下面的式子成立:
如果您熟悉复数而且需要使用它们,就要仔细阅读complex.h中的内容。
如果您使用C++,就应该知道C++的complex头文件提供了一种与C的complex.h头文件不同的处理复数的方法,前者的处理方法是基于类的。