Namespaces
Variants

Type-generic math (since C99)

From cppreference.net

头文件 <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 变体 cXXXf
  • double 变体 cXXX
  • long double 变体 cXXXl

上述规则的一个例外是 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 版本。
类型泛型
实数函数
变体
float double long double
atan2 atan2f atan2 atan2l
cbrt cbrtf cbrt cbrtl
ceil ceilf ceil ceill
copysign copysignf copysign copysignl
erf erff erf erfl
erfc erfcf erfc erfcl
exp2 exp2f exp2 exp2l
expm1 expm1f expm1 expm1l
fdim fdimf fdim fdiml
floor floorf floor floorl
fma fmaf fma fmal
fmax fmaxf fmax fmaxl
fmin fminf fmin fminl
fmod fmodf fmod fmodl
frexp frexpf frexp frexpl
hypot hypotf hypot hypotl
ilogb ilogbf ilogb ilogbl
ldexp ldexpf ldexp ldexpl
lgamma lgammaf lgamma lgammal
llrint llrintf llrint llrintl
llround llroundf llround llroundl
log10 log10f log10 log10l
log1p log1pf log1p log1pl
log2 log2f log2 log2l
logb logbf logb logbl
lrint lrintf lrint lrintl
lround lroundf lround lroundl
nearbyint nearbyintf nearbyint nearbyintl
nextafter nextafterf nextafter nextafterl
nexttoward nexttowardf nexttoward nexttowardl
remainder remainderf remainder remainderl
remquo remquof remquo remquol
rint rintf rint rintl
round roundf round roundl
scalbln scalblnf scalbln <a href

仅限复数函数

对于所有没有实数对应版本的复数函数,都存在一个泛型宏 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)