通用类型数学

来自cppreference.com
< c‎ | numeric

头文件<tgmath.h>包含头文件<math.h><complex.h>,并定义了几种通用类型宏。这些宏会根据参数类型决定要调用的实际函数。

对于每个宏,在<math.h>无后缀版函数中,所对应的实数类型为double的参数,即是所谓的通用化参数。(例如,pow的两个参数都是通用化参数,但scalbn只有第一个参数是通用化参数)

如下所述,使用<tgmath.h>宏时,传递给通用化参数的参数类型,会决定宏所选择的参数。若参数的类型与所选函数的参数类型不兼容,则行为未定义。(例如,若将复数参数传入实数限定的tgmath宏:float complex fc; ceil(fc)double complex dc; double d; fmax(dc, d)就是未定义行为的样例)

注意:通用类型宏在C99中曾被实现成实现定义的行为,但C11关键词_Generic使得以可移植方式实现这些宏成为可能。

目录

[编辑] 复数/实数通用类型宏

对于所有拥有实数及复数对应的函数,存在通用类型宏,会调用下列函数之一:

  • 实数函数:
  • float变体XXXf
  • double变体XXX
  • long double变体XXXl
  • 复数函数:
  • float变体cXXXf
  • double变体cXXX
  • long double变体cXXXl

上述规则的一个例外是fabs宏(见下表)。

调用的函数按以下方式决定:

  • 若通用化参数的任一参数为虚数,则行为会在每个函数参考页面上各自指定。(具体而言,sincostansinhcoshtanhasinatanasinhatanh调用实数函数,sincostansinhtanhasinatanasinhatanh的返回类型是虚数,而coshcosh的返回类型是实数)
  • 若通用化参数的任一参数为复数,则复数函数会得到调用,否则会调用实数函数。
  • 若通用化参数的任一参数为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 scalblnl
scalbn scalbnf scalbn scalbnl
tgamma tgammaf tgamma tgammal
trunc truncf trunc truncl

[编辑] 复数限定函数

对于所有没有实数对应的复数函数,存在通用类型宏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

[编辑] 参考

  • C11 standard (ISO/IEC 9899:2011):
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • C99 standard (ISO/IEC 9899:1999):
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)