Type-generic math (since C99)
头文件 <tgmath.h> 包含了头文件 <math.h> 和 <complex.h> ,并定义了若干 泛型宏 ,这些宏会根据参数类型决定调用哪个实数函数或在适用时调用哪个复数函数。
对于每个宏,其对应无后缀 <math.h> 函数中实际类型为 double 的参数被称为 泛型参数 (例如 pow 的两个参数都是泛型参数,但 scalbn 仅第一个参数是泛型参数)。
当使用 <tgmath.h> 中的宏时,传递给泛型参数的实参类型将根据下述规则决定宏选择哪个函数。如果实参类型与所选函数的参数类型 不兼容 ,则行为未定义(例如:向仅支持实数的 <tgmath.h> 宏传递复数实参: float complex fc ; ceil ( fc ) ; 或 double complex dc ; double d ; fmax ( dc, d ) ; 均为未定义行为的示例)。
注意:类型泛型宏在 C99 中以实现定义的方式实现,但 C11 关键字 _Generic 使得可以以可移植的方式实现这些宏。
目录 |
复数/实数泛型宏
对于所有同时具有实数版本和复数版本的函数,都存在一个泛型宏
XXX
,它会调用以下两者之一:
- 实数函数:
-
-
float
变体
XXXf -
double
变体
XXX -
long
double
变体
XXXl
-
float
变体
- 复杂函数:
-
-
float
变体
cXXXf -
double
变体
cXXX -
long
double
变体
cXXXl
-
float
变体
上述规则的一个例外是
fabs
宏(参见下表)。
要调用的函数按以下方式确定:
-
若泛型参数中任一参数为虚数,具体行为在各函数参考页单独说明(特别地,
sin、cos、tan、cosh、sinh、tanh、asin、atan、asinh和atanh会调用实数函数,其中sin、tan、sinh、tanh、asin、atan、asinh和atanh的返回类型为虚数,而cos和cosh的返回类型为实数)。 - 若泛型参数中任一参数为复数,则调用复数函数,否则调用实数函数。
- 若泛型参数中任一参数为 long double 类型,则调用 long double 版本。否则,若任一参数为 double 类型或整数类型,则调用 double 版本。否则调用 float 版本。
类型泛型宏如下:
|
泛型
宏 |
实数函数
变体 |
复数函数
变体 |
||||
|---|---|---|---|---|---|---|
| float | double | long double | float | double | long double | |
| fabs | fabsf | fabs | fabsl | cabsf | cabs | cabsl |
| exp | expf | exp | expl | cexpf | cexp | cexpl |
| log | logf | log | logl | clogf | clog | clogl |
| pow | powf | pow | powl | cpowf | cpow | cpowl |
| sqrt | sqrtf | sqrt | sqrtl | csqrtf | csqrt | csqrtl |
| sin | sinf | sin | sinl | csinf | csin | csinl |
| cos | cosf | cos | cosl | ccosf | ccos | ccosl |
| tan | tanf | tan | tanl | ctanf | ctan | ctanl |
| asin | asinf | asin | asinl | casinf | casin | casinl |
| acos | acosf | acos | acosl | cacosf | cacos | cacosl |
| atan | atanf | atan | atanl | catanf | catan | catanl |
| sinh | sinhf | sinh | sinhl | csinhf | csinh | csinhl |
| cosh | coshf | cosh | coshl | ccoshf | ccosh | ccoshl |
| tanh | tanhf | tanh | tanhl | ctanhf | ctanh | ctanhl |
| asinh | asinhf | asinh | asinhl | casinhf | casinh | casinhl |
| acosh | acoshf | acosh | acoshl | cacoshf | cacosh | cacoshl |
| atanh | atanhf | atanh | atanhl | catanhf | catanh | catanhl |
仅实数函数
对于所有没有复数版本的函数(除
modf
外),都存在一个泛型宏
XXX
,该宏会调用实数函数的任一变体:
-
float
变体
XXXf -
double
变体
XXX -
long
double
变体
XXXl
要调用的函数按以下方式确定:
- 如果泛型参数的任意实参为 long double ,则调用 long double 版本。否则,如果泛型参数的任意实参为 double ,则调用 double 版本。否则,调用 float 版本。
仅限复数函数
对于所有没有实数对应版本的复数函数,都存在一个泛型宏
cXXX
,它会调用复数函数的任一变体:
要调用的函数按以下方式确定:
- 如果泛型参数的任意参数为实数、复数或虚数,则调用相应的复数函数。
|
泛型
宏 |
复数函数
变体 |
||
|---|---|---|---|
| float | double | long double | |
| carg | cargf | carg | cargl |
| conj | conjf | conj | conjl |
| creal | crealf | creal | creall |
| cimag | cimagf | cimag | cimagl |
| cproj | cprojf | cproj | cprojl |
示例
#include <stdio.h> #include <tgmath.h> int main(void) { int i = 2; printf("sqrt(2) = %f\n", sqrt(i)); // 参数类型为 int,调用 sqrt float f = 0.5; printf("sin(0.5f) = %f\n", sin(f)); // 参数类型为 float,调用 sinf float complex dc = 1 + 0.5*I; float complex z = sqrt(dc); // 参数类型为 float complex,调用 csqrtf printf("sqrt(1 + 0.5i) = %f+%fi\n", creal(z), // 参数类型为 float complex,调用 crealf cimag(z)); // 参数类型为 float complex,调用 cimagf }
输出:
sqrt(2) = 1.414214 sin(0.5f) = 0.479426 sqrt(1 + 0.5i) = 1.029086+0.242934i
参考文献
- C23 标准 (ISO/IEC 9899:2024):
-
- 7.25 泛型数学 <tgmath.h> (页码: 待定)
- C17 标准 (ISO/IEC 9899:2018):
-
- 7.25 泛型数学 <tgmath.h> (页码: 272-273)
- C11 标准 (ISO/IEC 9899:2011):
-
- 7.25 泛型数学 <tgmath.h> (页码: 373-375)
- C99标准(ISO/IEC 9899:1999):
-
- 7.22 泛型数学 <tgmath.h> (页码:335-337)