头文件包含头文件和,并定义了几个类型泛型宏,它们根据参数的类型确定哪些实际的或适用的复杂函数。
对于每个宏,参数的相应的实数类型在未被混合的math.h函数中是double的,被称为泛型参数(例如pow的两个参数都是泛型参数,但只有scalbn的第一个参数是泛型参数)。
当使用宏时,传递给泛型参数的参数类型决定了如下所述由宏选择哪个函数。 如果参数的类型与所选函数的参数类型不兼容,则行为是未定义的(例如,如果将一个复杂参数传递给实数tgmath宏: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
上述规则的一个例外是晶圆厂宏(参见下表)。
要调用的函数如下确定:
如果通用参数的任何参数都是虚构的,则在每个函数参考页面上分别指定行为(特别是,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调用变体。
类型通用宏如下所示:
Type-generic macroReal function variantsComplex function variantsfloatdoublelong doublefloatdoublelong double
fabsfabsffabsfabslcabsfcabscabsl
expexpfexpexplcexpfcexpcexpl
loglogflogloglclogfclogclogl
powpowfpowpowlcpowfcpowcpowl
sqrtsqrtfsqrtsqrtlcsqrtfcsqrtcsqrtl
sinsinfsinsinlcsinfcsincsinl
coscosfcoscoslccosfccosccosl
tantanftantanlctanfctanctanl
asinasinfasinasinlcasinfcasincasinl
acosacosfacosacoslcacosfcacoscacosl
atanatanfatanatanlcatanfcatancatanl
sinhsinhfsinhsinhlcsinhfcsinhcsinhl
coshcoshfcoshcoshlccoshfccoshccoshl
tanhtanhftanhtanhlctanhfctanhctanhl
asinhasinhfasinhasinhlcasinhfcasinhcasinhl
acoshacoshfacoshacoshlcacoshfcacoshcacoshl
atanhatanhfatanhatanhlcatanhfcatanhcatanhl
真正的唯一功能
对于没有复杂对象的所有函数,除了modf之外,还有一个类型通用宏XXX存在,它调用实函数的变体之一:
float 变型 XXXf
double 变型 XXX
long double 变型 XXXl
要调用的函数如下确定:
如果通用参数的任何参数是long double,则调用long double变体。 否则,如果泛型参数的任何参数是双精度型,则调用双精度型。 否则,调用float变量。
Type-generic macroReal function variantsfloatdoublelong double
atan2atan2fatan2atan2l
cbrtcbrtfcbrtcbrtl
ceilceilfceilceill
copysigncopysignfcopysigncopysignl
erferfferferfl
erfcerfcferfcerfcl
exp2exp2fexp2exp2l
expm1expm1fexpm1expm1l
fdimfdimffdimfdiml
floorfloorffloorfloorl
fmafmaffmafmal
fmaxfmaxffmaxfmaxl
fminfminffminfminl
fmodfmodffmodfmodl
frexpfrexpffrexpfrexpl
hypothypotfhypothypotl
ilogbilogbfilogbilogbl
ldexpldexpfldexpldexpl
lgammalgammaflgammalgammal
llrintllrintfllrintllrintl
llroundllroundfllroundllroundl
log10log10flog10log10l
log1plog1pflog1plog1pl
log2log2flog2log2l
logblogbflogblogbl
lrintlrintflrintlrintl
lroundlroundflroundlroundl
nearbyintnearbyintfnearbyintnearbyintl
nextafternextafterfnextafternextafterl
nexttowardnexttowardfnexttowardnexttowardl
remainderremainderfremainderremainderl
remquoremquofremquoremquol
rintrintfrintrintl
roundroundfroundroundl
scalblnscalblnfscalblnscalblnl
scalbnscalbnfscalbnscalbnl
tgammatgammaftgammatgammal
trunctruncftrunctruncl
复杂功能
对于所有没有实际对应项的复数函数,都存在一个类型通用宏cXXX,它调用复杂函数的任何一种变体:
float complex 变型 cXXXf
double complex 变型 cXXX
long double complex 变型 cXXXl
要调用的函数如下确定:
如果通用参数的任何参数是实数,复数或虚数,则调用相应的复数函数。
Type-generic macroComplex function variantsfloatdoublelong double
cargcargfcargcargl
conjconjfconjconjl
crealcrealfcrealcreall
cimagcimagfcimagcimagl
cprojcprojfcprojcprojl
例
#include #include
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.414214sin(0.5f) = 0.479426sqrt(1 + 0.5i) = 1.029086+0.242934i
参考
C11标准(ISO / IEC 9899:2011):7.25类型通用数学(p:373-375)
C99标准(ISO / IEC 9899:1999):7.22类型通用数学(p:335-337)