19.6 泛型数学
<tgmath.h>(type-generic math)提供一组“泛型”宏,让你可以用一个名字调用到正确的数学函数版本:
- 当实参是
float时,选择带f后缀的版本(如sinf)。 - 当实参是
double时,选择不带后缀的版本(如sin)。 - 当实参是
long double时,选择带l后缀的版本(如sinl)。 - 当实参是复数类型时(见 19.5),选择
<complex.h>中的对应版本(如csin)。
这些宏只决定调用哪个函数,被调函数的定义域、精度和错误报告方式与直接调用该函数时相同。
1. 示例
c
#include <tgmath.h>
#include <stdio.h>
int main(void) {
float x = 0.5f;
double y = 0.5;
printf("%.6f\n", sin(x)); /* 实参是 float:等价于 sinf(x) */
printf("%.6f\n", sin(y)); /* 实参是 double:等价于 sin(y) */
return 0;
}1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
常见数学库会输出:
bash
0.479426 0.479426
注意
<tgmath.h>的接口是宏,不应把带副作用的表达式(例如i++)作为实参。- 不需要泛型时,直接使用
<math.h>中带明确后缀的函数名更清楚,尤其是需要强制使用某一精度(例如long double)的场合。
2. 实参类型决定选择结果
选择依据是实参类型,而不是接收结果的对象的类型。即使把结果赋给 double 对象,只要实参是 float,调用的仍是 float 版本。需要固定使用某一精度时,应先把实参显式转换为目标类型:
c
#include <tgmath.h>
double f(float x) {
return sin((double)x); /* 调用 double 版本的 sin */
}1
2
3
4
5
2
3
4
5
3. 习题
#11905
⚡3⏳2
写一个程序:分别以 float 与 double 读入同一个数值,调用 <tgmath.h> 的 sqrt 并输出结果。
要求:
- 程序应同时包含
float与double两条路径; - 输出时分别标注类型;
- 输入失败时退出。