3.4 IEEE 支持函数
本节介绍了 IEEE 推荐的函数,这些函数提供有用的值 ieee_flags、ieee_retrospective 以及 standard_arithmetic 和 nonstandard_arithmetic。有关函数 ieee_flags 和 ieee_handler 的更多信息,请参阅异常和异常处理。
3.4.1 ieee_functions(3m) 和 ieee_sun(3m)
ieee_functions(3m) 和 ieee_sun(3m) 介绍的函数提供了 IEEE 标准要求的功能或其附录中推荐的功能。这些函数是按有效位掩码运算实现的。
表 18 ieee_functions(3m)
|
|
math.h
|
头文件
|
copysign(x,y)
|
x 及 y 的符号位
|
fabs(x)
|
x 的绝对值
|
fmod(x, y)
|
x 除以 y 所得的余数
|
ilogb(x)
|
以 2 为基数的整数格式 x 无偏置指数
|
nextafter(x,y)
|
在 y 方向上,x 后面的下一个可表示的数
|
remainder(x,y)
|
x 除以 y 所得的余数
|
scalbn(x,n)
|
x × 2n
|
|
表 19 ieee_sun(3m)
|
|
sunmath.h
|
头文件
|
fp_class(x)
|
分类函数
|
isinf(x)
|
分类函数
|
isnormal(x)
|
分类函数
|
issubnormal(x)
|
分类函数
|
iszero(x)
|
分类函数
|
signbit(x)
|
分类函数
|
nonstandard_arithmetic(void)
|
启用非标准模式
|
standard_arithmetic(void)
|
启用标准模式
|
ieee_retrospective(*f)
|
n/a
|
|
remainder(x,y) 是在 IEEE 标准 754-1985 中指定的运算。remainder(x,y) 和 fmod(x,y) 的不同之处在于,remainder(x,y) 返回结果的符号可能与 x 或 y 的符号不一致,而 fmod(x,y) 返回结果的符号始终与 x 一致。这两个函数均返回精确的结果,并且不生成不精确异常。
表 20 从 Fortran 中调用 ieee_functions
|
|
|
|
copysign(x,y)
|
t=r_copysign(x,y)
|
z=d_copysign(x,y)
|
z=q_copysign(x,y)
|
ilogb(x)
|
i=ir_ilogb(x)
|
i=id_ilogb(x)
|
i=iq_ilogb(x)
|
nextafter(x,y)
|
t=r_nextafter(x,y)
|
z=d_nextafter(x,y)
|
z=q_nextafter(x,y)
|
scalbn(x,n)
|
t=r_scalbn(x,n)
|
z=d_scalbn(x,n)
|
z=q_scalbn(x,n)
|
signbit(x)
|
i=ir_signbit(x)
|
i=id_signbit(x)
|
i=iq_signbit(x)
|
|
表 21 从 Fortran 中调用 ieee_sun
|
|
|
|
signbit(x)
|
i=ir_signbit(x)
|
i=id_signbit(x)
|
i=iq_signbit(x)
|
|
注 -
在使用 d_function 和 q_function 的 Fortran 程序中,必须将前一个函数声明为双精度,而将后一个函数声明为 REAL*16。
3.4.2 ieee_values(3m)
无穷大、NaN、最大和最小正浮点数等 IEEE 值是由 ieee_values(3m) 手册页中介绍的函数提供的。 表 22、表 23、表 24和表 25中显示了 ieee_values(3m) 函数提供的值的十进制值及其十六进制 IEEE 表示形式。
表 22 IEEE 值:单精度
|
|
|
最大正规数 |
3.40282347e+38 7f7fffff |
r = max_normalf(); r = r_max_normal() |
最小正规数 |
1.17549435e–38 00800000 |
r = min_normalf(); r = r_min_normal() |
最大次正规数 |
1.17549421e–38 007fffff |
r = max_subnormalf(); r = r_max_subnormal() |
最小次正规数 |
1.40129846e–45 00000001 |
r = min_subnormalf(); r = r_min_subnormal() |
∞ |
Infinity 7f800000 |
r = infinityf(); r = r_infinity() |
quiet NaN(静态 NaN) |
NaN 7fffffff |
r = quiet_nanf(0); r = r_quiet_nan(0) |
信号 NaN |
NaN 7f800001 |
r = signaling_nanf(0); r = r_signaling_nan(0) |
|
表 23 IEEE 值:双精度
|
|
|
最大正规数 |
1.7976931348623157e+308
7fefffff ffffffff |
d = max_normal(); d = d_max_normal() |
最小正规数 |
2.2250738585072014e–308
00100000 00000000 |
d = min_normal(); d = d_min_normal() |
最大次正规数 |
2.2250738585072009e–308
000fffff ffffffff |
d = max_subnormal(); d = d_max_subnormal() |
最小次正规数 |
4.9406564584124654e–324
00000000 00000001 |
d = min_subnormal(); d = d_min_subnormal() |
∞
|
Infinity
7ff00000 00000000 |
d = infinity(); d = d_infinity() |
quiet NaN(静态 NaN) |
NaN
7fffffff ffffffff |
d = quiet_nan(0); d = d_quiet_nan(0) |
信号 NaN |
NaN
7ff00000 00000001 |
d = signaling_nan(0); d = d_signaling_nan(0) |
|
表 24 IEEE 值:四倍精度
|
|
|
最大正规数 |
1.1897314953572317650857593266280070e+4932
7ffeffff ffffffff ffffffff ffffffff |
q = max_normall(); q = q_max_normal() |
最小正规数 |
3.3621031431120935062626778173217526e–4932
00010000 00000000 00000000 00000000 |
q = min_normall(); q = q_min_normal() |
最大次正规数 |
3.3621031431120935062626778173217520e–4932
0000ffff ffffffff ffffffff ffffffff |
q = max_subnormall(); q = q_max_subnormal() |
最小次正规数 |
6.4751751194380251109244389582276466e–4966
00000000 00000000 00000000 00000001 |
q = min_subnormall(); q = q_min_subnormal() |
∞
|
Infinity
7fff0000 00000000 00000000 00000000 |
q = infinityl(); q = q_infinity() |
quiet NaN(静态 NaN) |
NaN
7fff8000 00000000 00000000 00000000 |
q = quiet_nanl(0); q = q_quiet_nan(0) |
信号 NaN |
NaN
7fff0000 00000000 00000000 00000001 |
q = signaling_nanl(0); q = q_signaling_nan(0) |
|
表 25 IEEE 值:双扩展精度 (x86)
|
|
|
最大正规数 |
1.18973149535723176505e+4932
7ffe ffffffff ffffffff |
x = max_normall(); |
最小正正规数 |
3.36210314311209350626e–4932
0001 80000000 00000000 |
x = min_normall(); |
最大次正规数 |
3.36210314311209350608e–4932
0000 7fffffff ffffffff |
x = max_subnormall(); |
最小正次正规数 |
1.82259976594123730126e–4951
0000 00000000 00000001 |
x = min_subnormall(); |
∞
|
Infinity
7fff 80000000 00000000 |
x = infinityl(); |
quiet NaN(静态 NaN) |
NaN
7fff c0000000 00000000 |
x = q |
信号 NaN |
NaN
7fff 80000000 00000001 |
x = signaling_nanl(0); |
|
3.4.3 ieee_flags(3m)
ieee_flags (3m) 是用于以下功能的 Oracle 接口:
查询或设置舍入方向模式
查询或设置舍入精度模式
检查、清除或设置已发生异常标志
调用 ieee_flags(3m) 的语法为:
i = ieee_flags(action, mode, in, out);
可能作为参数值的 ASCII 字符串如表 26所示:
表 26 ieee_flags 的参数值
|
|
|
action |
char * |
get、set、clear、clearall |
mode |
char * |
direction、precision、exception |
in |
char * |
nearest、tozero、negative、positive、extended、double、single、inexact、
division、underflow、overflow、invalid、all、common |
out |
char ** |
nearest、tozero、negative、positive、extended、double、single、inexact、
division、underflow、overflow、invalid、all、common |
|
ieee_flags(3m) 手册页详细介绍了这些参数。
以下段落介绍了可使用 ieee_flags 修改的某些算法功能。第 4 章中包含有关 ieee_flags 和 IEEE 异常标志的更多信息。
如果 mode 为 direction,则说明指定的操作适用于当前的舍入方向。可能的舍入方向为:向最接近的值舍入、向零舍入、向 +· 舍入或向 -· 舍入。IEEE 缺省舍入方向为向最接近的值舍入。这意味着,如果运算的数学结果恰好位于两个相邻的可表示的数字之间,则提供最接近数学结果的数字。(如果数学结果恰好位于两个最接近的可表示的数字中间,会将最低有效位为零的数字作为结果提供。有时将向最接近的值舍入模式称为向最接近的偶数舍入以进行强调。)
向零舍入是 IEEE 之前的很多计算机的工作方式,且在数学计算中与将结果截断操作一致。 例如,如果将 2/3 舍入到 6 个十进制数字,则当舍入模式为向最接近的值舍入时结果为 .666667,当舍入模式为向零舍入时结果为 .666666。
在使用 ieee_flags 检查、清除或设置舍入方向时,四个可能的输入参数值如表 27所示。
表 27 ieee_flags 舍入方向的输入值
|
|
action |
get、set、clear、clearall |
in |
nearest、tozero、negative、positive |
out |
nearest、tozero、negative、positive |
|
如果 mode 为 precision,则说明指定的操作适用于当前的舍入精度。在基于 x86 的系统上,可能的舍入精度为:单、双和扩展精度。缺省的舍入精度为扩展精度;在这种模式下,提供 x87 浮点寄存器结果的算术运算将其结果舍入到使用扩展双寄存器格式的完整 64 位精度。当舍入精度为单或双精度时,提供 x87 浮点寄存器结果的算术运算将其结果分别舍入到 24 或 53 个有效位。虽然大多数程序在使用扩展舍入精度时生成很准确的结果(即便不是最准确的结果),但某些要求严格遵循 IEEE 算法语义的程序在扩展舍入精度模式下无法正常工作,必须将舍入精度相应地设置为单精度或双精度才能运行这些程序。
在使用 SPARC 处理器的系统上不能设置舍入精度。在这些系统上,使用 mode = precision 调用 ieee_flags 对计算没有影响。
最后,如果 mode 为 exception,则说明指定的操作适用于当前的 IEEE 异常标志。有关使用 ieee_flags 检查和控制 IEEE 异常标志的更多信息,请参见异常和异常处理。
3.4.4 ieee_retrospective(3m)
libsunmath 函数 ieee_retrospective 打印有关未处理异常和非标准 IEEE 模式的信息。它报告:
未处理异常。
启用的陷阱。
如果将舍入方向或精度设置为非缺省值。
如果非标准算法生效的话。
从硬件浮点状态寄存器获得所需的信息。
ieee_retrospective 打印有关引发的异常标志以及启用陷阱 的异常的信息。不应混淆这两种截然不同的信息(即使它们有关联也是如此)。如果引发异常标志,则该异常是在执行程序过程中某一时刻发生的。如果为异常启用了陷阱,则异常可能并没有实际发生,但如果发生了,会提供 SIGFPE 信号。ieee_retrospective 消息用于提示您有关可能需要调查的异常的信息(如果引发了异常标志),或者提示您信号处理程序可能已处理了异常(如果启用了异常的陷阱)。异常和异常处理讨论了异常、信号和陷阱,并说明如何调查引发异常的原因。
程序可以随时显式调用 ieee_retrospective。在 –f77 兼容模式下使用 f95 编译的 Fortran 程序会在其退出前自动调用 ieee_retrospective。在缺省模式下使用 f95 编译的 C/C++ 程序和 Fortran 程序不会自动调用 ieee_retrospective。
注意,在缺省情况下,f95 编译器会对常见异常启用捕获,因此,除非有程序显式禁用捕获或者安装 SIGFPE 处理程序,否则在发生此类异常时程序会立即中止。在 –f77 兼容模式下,编译器并不启用捕获,因此当发生浮点异常时,程序继续执行,并在退出时通过 ieee_retrospective 输出报告这些异常。
调用此函数的语法为:
对于 C 函数,参数 fp 指定写入输出的文件。Fortran 函数始终在 stderr 上打印输出。
以下示例显示 6 个 ieee_retrospective 警告消息中的 4 个:
Note: IEEE floating-point exception flags raised:
Inexact; Underflow;
Rounding direction toward zero
IEEE floating-point exception traps enabled:
overflow;
See the Numerical Computation Guide, ieee_flags(3M),
ieee_handler(3M), ieee_sun(3m)
只有在启用捕获或引发异常时,才会出现警告消息。
可以在 Fortran 程序中使用三种方法之一来禁止 ieee_retrospective 消息。 一种方法是清除所有未处理的异常,禁用陷阱,并在程序退出前恢复舍入到最接近的值、扩展精度和标准模式。为此,请按如下方式调用 ieee_flags、ieee_handler 和 standard_arithmetic:
character*8 out
i = ieee_flags('clearall', '', '', out)
call ieee_handler('clear', 'all', 0)
call standard_arithmetic()
注 -
建议不要不调查其原因就清除未处理的异常。
另一种避免看到 ieee_retrospective 消息的方法是将 stderr 重定向到某个文件。当然,如果程序还将其他非 ieee_retrospective 消息的输出发送到 stderr,则不应使用这种方法。
第三种方法是在程序中包含伪 ieee_retrospective 函数,例如:
subroutine ieee_retrospective
return
end
3.4.5 nonstandard_arithmetic(3m)
正如IEEE 运算中所介绍的一样,IEEE 算法使用渐进下溢来处理出现下溢的结果。 在某些基于 SPARC 的系统上,渐进下溢通常是使用算法的软件仿真部分实现的。 如果很多计算都出现下溢,其性能可能会下降。
要获取某些有关特定程序中是否出现这种情况的信息,可以使用 ieee_retrospective 或 ieee_flags 来确定是否发生了下溢异常,并检查程序使用的系统时间。如果操作系统中的程序花费了非常多的时间并引发了下溢异常,则渐进下溢可能是引发该问题的原因。在这种情况下,使用非 IEEE 算法可以加快程序的执行速度。
函数 nonstandard_arithmetic 在支持非 IEEE 算法模式的处理器上启用这些模式。在 SPARC 系统上,该函数在浮点状态寄存器中设置 NS(nonstandard arithmetic, 非标准算法)位。在支持 SSE 指令的 x86 系统上,该函数在 MXCSR 寄存器中设置了 FTZ(flush to zero, 刷新为零)位;它还在支持 DAZ(denormals are zero, 非正规数为零)位的处理器上的 MXCSR 寄存器中设置该位。注意,非标准模式的作用因处理器而异,并且可能会导致可靠软件出错。建议不要使用非标准模式以确保正常使用。
函数 standard_arithmetic 将硬件重置为使用缺省 IEEE 算法。这两种函数对只提供缺省 IEEE 754 样式的算法的处理器没有影响。SPARC T4 就是一种此类处理器。