类型泛型数学 (自 C99)
来自 cppreference.cn
头文件 <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
、tag
、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)); // argument type is int, calls sqrt float f = 0.5; printf("sin(0.5f) = %f\n", sin(f)); // argument type is float, calls sinf float complex dc = 1 + 0.5*I; float complex z = sqrt(dc); // argument type is float complex, calls csqrtf printf("sqrt(1 + 0.5i) = %f+%fi\n", creal(z), // argument type is float complex, calls crealf cimag(z)); // argument type is float complex, calls 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)