1 绝对值函数
1.1 函数概述
函数名 | 函数原型 | 功能描述 | 注意事项 |
---|---|---|---|
abs | int abs(int j); | 返回整数 j 的绝对值 | 需要包含头文件 <stdlib.h> |
fabs | double fabs(double x); | 返回浮点数 x 的绝对值 | 需要包含头文件 <math.h> |
fabsf | float fabsf(float x); | 返回 float 类型浮点数 x 的绝对值 | 需要包含头文件 <math.h> |
fabsl | long double fabsl(long double x); | 返回 long double 类型浮点数 x 的绝对值 | 需要包含头文件 <math.h> |
- 类型适配:不同绝对值函数针对不同数据类型设计,abs 用于整数,fabs、fabsf、fabsl 分别用于不同精度的浮点数,根据实际数据类型选择合适函数,能确保计算准确性和效率。
- 头文件依赖:明确各函数所需头文件,避免因未包含正确头文件导致编译错误,保证程序能正常调用这些绝对值计算函数 。
1.2 案例演示
#include <stdio.h>
#include <stdlib.h> // 包含 abs 函数的头文件
#include <math.h> // 包含 fabs、fabsf 和 fabsl 函数的头文件
int main()
{
// 整数绝对值示例
int int_num = -10;
printf("abs(%d) = %d\n", int_num, abs(int_num));
// double 类型浮点数绝对值示例
double double_num = -3.14;
printf("fabs(%f) = %f\n", double_num, fabs(double_num));
// float 类型浮点数绝对值示例
float float_num = -3.14f;
printf("fabsf(%f) = %f\n", float_num, fabsf(float_num));
// long double 类型浮点数绝对值示例
long double long_double_num = -3.14L;
printf("fabsl(%Lf) = %Lf\n", long_double_num, fabsl(long_double_num));
return 0;
}
程序在 VS Code 中的运行结果如下所示:
2 数学运算函数
2.1 函数概述
函数名 | 函数原型 | 功能描述 | 注意事项 |
---|---|---|---|
pow | double pow(double x, double y); | 计算 x 的 y 次幂 | 需要包含头文件 <math.h>,且当 x 为负数且 y 不是整数时,结果可能是复数,但 C 标准库不直接支持复数运算,此时行为未定义。 |
sqrt | double sqrt(double x); | 计算 x 的平方根 | 需要包含头文件 <math.h>,且 x 必须是非负数,否则结果未定义(可能返回 NaN 或导致程序错误)。 |
cbrt | double cbrt(double x); | 计算 x 的立方根 | 需要包含头文件 <math.h>,此函数对所有实数 x 都有定义,包括负数。 |
exp | double exp(double x); | 计算自然指数 e^x(其中 e 是自然对数的底数) | 需要包含头文件 <math.h>,x 可以是任意实数。 |
log | double log(double x); | 计算 x 的自然对数(即 ln(x)) | 需要包含头文件 <math.h>,且 x 必须是正数,否则结果未定义(可能返回 NaN 或导致程序错误)。 |
log10 | double log10(double x); | 计算 x 的常用对数(即 log10(x)) | 需要包含头文件 <math.h>,且 x 必须是正数,否则结果未定义(可能返回 NaN 或导致程序错误)。 |
- 正确使用头文件:这些数学函数均需包含 <math.h> 头文件,这是调用函数的前提,否则编译器无法识别函数原型,会导致编译错误。
- 参数范围限制:
- pow 函数在处理负数底数(x)和非整数指数(y)时行为未定义,编程时需确保参数组合在合理范围内,避免出现不可预期结果。
- sqrt 和 log、log10 函数对参数有严格限制,参数必须为非负数或正数,否则结果未定义,可能引发程序错误或得到无效结果(如 NaN),调用前务必检查参数有效性。
- 函数特性差异:cbrt 函数对所有实数都有定义,包括负数,这是其与 sqrt 等函数的重要区别,根据计算需求选择合适函数。
- 指数运算适用性:exp 函数能处理任意实数指数,在涉及自然指数计算场景中非常实用,但要注意其结果可能因指数过大或过小导致溢出或精度问题。
2.2 案例演示
#include <stdio.h>
#include <math.h> // 包含所有数学函数的头文件
int main()
{
double x = 2.0;
double y = 3.0;
double e = M_E; // 使用 math.h 中定义的常量 M_E 表示 e
// pow 函数示例
printf("pow(%f, %f) = %f\n", x, y, pow(x, y)); // 8.0
// sqrt 函数示例
printf("sqrt(%f) = %f\n", 16.0, sqrt(16.0)); // 4.0
// cbrt 函数示例
printf("cbrt(%f) = %f\n", -64.0, cbrt(-64.0)); // -4.0
// exp 函数示例
printf("exp(%f) = %f\n", 0.0, exp(0.0)); // 1.0
// log 函数示例
printf("log(%f) = %f\n", 2.7182, log(2.7182)); // 接近 1.0
// 输出 lne
printf("log(%f) = %f\n", e, log(e)); // 1.0
// log10 函数示例
printf("log10(%f) = %f\n", 100.0, log10(100.0)); // 2.0
return 0;
}
程序在 VS Code 中的运行结果如下所示:
3 取整与舍入函数
3.1 函数概述
函数名 | 函数原型 | 功能描述 | 注意事项 |
---|---|---|---|
floor | double floor(double x); | 计算不超过 x 的最大整数(向下取整) | 需要包含头文件 <math.h>,结果是一个 double 类型的整数,但实际值是整数。 |
ceil | double ceil(double x); | 计算不小于 x 的最小整数(向上取整) | 需要包含头文件 <math.h>,结果是一个 double 类型的整数,但实际值是整数。 |
round | double round(double x); | 对 x 进行四舍五入,返回最接近的整数(以 double 类型表示) | 需要包含头文件 <math.h>,当 x 正好位于两个整数中间时(例如 1.5),结果会向绝对值更大的方向取整(即 2.0 而不是 1.0)。 |
trunc | double trunc(double x); | 截断 x 的小数部分,返回整数部分(以 double 类型表示) | 需要包含头文件 <math.h>,此函数直接去掉小数部分,不考虑四舍五入,结果是一个 double 类型的整数。 |
- 头文件依赖:所有这些取整函数都需包含 <math.h> 头文件,这是调用函数的基本要求,缺少头文件会导致编译无法通过。
- 结果类型:尽管这些函数返回的结果实际值是整数,但类型为 double。在后续需要整数运算或存储时,可能需要进行类型转换,以避免类型不匹配问题。
- 取整规则差异:
- floor 和 ceil 分别用于向下和向上取整,根据实际需求选择合适的函数,比如在需要确保结果不大于或不小于某个值时使用。
- round 的四舍五入规则在处理位于两个整数中间的值时,会向绝对值更大的方向取整,这与常规的四舍五入认知一致,但在某些对取整方向有特殊要求的场景中需谨慎使用。
- trunc 直接截断小数部分,不考虑四舍五入,适用于只需要简单去掉小数部分的场景,与其他取整函数有明显区别,使用时需明确需求。
3.2 案例演示
#include <stdio.h>
#include <math.h> // 包含 floor, ceil, round, trunc 函数的头文件
int main()
{
// 向下取整 3.1 3.5 3.9
printf("floor(3.1) = %f\t", floor(3.1)); // 输出 floor(3.1) = 3.000000
printf("floor(3.5) = %f\t", floor(3.5)); // 输出 floor(3.5) = 3.000000
printf("floor(3.9) = %f\n", floor(3.9)); // 输出 floor(3.9) = 3.000000
// 向上取整 3.1 3.5 3.9
printf("ceil(3.1) = %f\t", ceil(3.1)); // 输出 ceil(3.1) = 4.000000
printf("ceil(3.5) = %f\t", ceil(3.5)); // 输出 ceil(3.5) = 4.000000
printf("ceil(3.9) = %f\n", ceil(3.9)); // 输出 ceil(3.9) = 4.000000
// 四舍五入 -1.50 1.50 -1.45 1.45
printf("round(-1.50) = %f\t", round(-1.50)); // 输出 round(-1.50) = -2.000000
printf("round(1.50) = %f\n", round(1.50)); // 输出 round(1.50) = 2.000000
printf("round(-1.45) = %f\t", round(-1.45)); // 输出 round(-1.45) = -1.000000
printf("round(1.45) = %f\n", round(1.45)); // 输出 round(1.45) = 1.000000
// 截断 -9.99 9.99 -9.01 9.01
printf("trunc(-9.99) = %f\t", trunc(-9.99)); // 输出 trunc(-9.99) = -9.000000
printf("trunc(9.99) = %f\n", trunc(9.99)); // 输出 trunc(9.99) = 9.000000
printf("trunc(-9.01) = %f\t", trunc(-9.01)); // 输出 trunc(-9.01) = -9.000000
printf("trunc(9.01) = %f\n", trunc(9.01)); // 输出 trunc(9.01) = 9.000000
return 0;
}
程序在 VS Code 中的运行结果如下所示:
4 分解与组合函数
4.1 函数概述
函数名 | 函数原型 | 功能描述 | 注意事项 |
---|---|---|---|
fmod | double fmod(double x, double y); | 计算浮点数 x 除以 y 的余数,即 x%y | 需要包含头文件 <math.h>,当 y 为 0 时,行为是未定义的。 |
modf | double modf(double x, double *iptr); | 将浮点数 x 分离为整数部分和小数部分,整数部分存储在 iptr 中,函数返回小数部分 | 需要包含头文件 <math.h>,小数部分和整数部分都以 double 类型返回。 |
frexp | double frexp(double x, int *exp); | 将浮点数 x 分解为尾数 m 和指数 e,使得 x = m * 2^e,尾数 m 的范围是 [0.5, 1) 或 0 | 需要包含头文件<math.h>,尾数 m 是函数的返回值,指数 e 存储在第二个参数 exp 指向的变量中(通过指针传递)。 |
ldexp | double ldexp(double x, int exp); | 将尾数 x 和指数 exp 组合为浮点数 x * 2^exp | 需要包含头文件 <math.h>,用于将通过 frexp 分解后的尾数和指数重新组合成原始浮点数。 |
- 头文件统一要求:这些函数均需包含 <math.h> 头文件,这是调用它们的基本前提,缺少该头文件会导致编译错误,无法正常使用函数功能。
- 特殊参数处理:
- fmod 函数中,当除数 y 为 0 时行为未定义,在编程时必须确保 y 不为 0,否则程序可能出现不可预期的结果甚至崩溃。
- modf 函数通过指针参数 iptr 返回整数部分,调用时需确保指针有效且指向可写的内存空间,避免出现空指针或内存访问错误。
- frexp 函数同样使用指针参数 exp 返回指数部分,使用时也要保证指针有效,同时要注意尾数 m 的范围特性,合理利用其分解结果。
- 函数组合应用:frexp 和 ldexp 函数常常配合使用,frexp 用于将浮点数分解为尾数和指数,ldexp 则用于将分解后的尾数和指数重新组合成原始浮点数,这种组合在需要深入处理浮点数内部表示的场景中非常有用,例如科学计算或特定算法实现。
4.2 案例演示
#include <stdio.h>
#include <math.h> // 包含 fmod, modf, frexp, ldexp 函数的头文件
int main()
{
double x = 13.375; // 要分解的数
double y = 3.0; // 分解的基数
int exp; // 指数
double m, ipart, fpart, reconstructed; // 分解后的整数部分、小数部分、重新组合后的数
// fmod 示例
double remainder = fmod(x, y);
printf("fmod(%f, %f) = %f\n", x, y, remainder); // 1.375
// modf 示例
fpart = modf(x, &ipart); // 返回小数部分,整数部分存储在 ipart 中
printf("modf(%f) = ipart = %f, fpart = %f\n", x, ipart, fpart);
// frexp 示例
m = frexp(x, &exp); // 返回尾数部分,指数存储在 exp 中
printf("frexp(%f) = m = %f, e = %d\n", x, m, exp);
// ldexp 示例
reconstructed = ldexp(m, exp); // 根据尾数部分和指数重新组合成数
printf("ldexp(%f, %d) = %f\n", m, exp, reconstructed);
return 0;
}
程序在 VS Code 中的运行结果如下所示:
5 三角函数
5.1 函数概述
函数名 | 函数原型 | 功能描述 | 注意事项 |
---|---|---|---|
sin | double sin(double x); | 计算角度 x(以弧度表示)的正弦值 | 需要包含头文件 <math.h>,参数 x 应为弧度值,而非角度值。若输入为角度,需先转换为弧度(乘以 π/180)。 |
cos | double cos(double x); | 计算角度 x(以弧度表示)的余弦值 | 需要包含头文件 <math.h>,参数 x 应为弧度值,注意与角度的转换。 |
tan | double tan(double x); | 计算角度 x(以弧度表示)的正切值 | 需要包含头文件 <math.h>,参数 x 为弧度值,且当 x 接近 π/2 + kπ(k 为整数)时,结果可能趋向无穷大或产生数值不稳定。 |
- 头文件依赖:所有三角函数均需包含 <math.h> 头文件,这是调用这些函数的前提条件,缺少该头文件会导致编译错误。
- 参数单位:三角函数的参数 x 均以弧度为单位,而非角度。在编程时,若输入为角度,需先进行弧度转换(乘以 π/180),以确保计算结果的正确性。
- 数值稳定性:tan 函数在 x 接近 π/2 + kπ(k 为整数)时,结果可能趋向无穷大或产生数值不稳定,使用时需注意参数范围,避免出现不可预期的结果。
5.2 案例演示
#include <stdio.h>
#include <math.h> // 包含数学函数头文件
#define PI 3.14159265358979323846 // 定义 π 的近似值
int main()
{
double angle_degrees = 45.0; // 角度值
double angle_radians = angle_degrees * PI / 180.0; // 将角度转换为弧度
// 计算并输出正弦、余弦和正切值
printf("sin(%.2f°) = %.6f\n", angle_degrees, sin(angle_radians));
printf("cos(%.2f°) = %.6f\n", angle_degrees, cos(angle_radians));
printf("tan(%.2f°) = %.6f\n", angle_degrees, tan(angle_radians));
return 0;
}
程序在 VS Code 中的运行结果如下所示:
6 反三角函数
6.1 函数概述
函数名 | 函数原型 | 功能描述 | 注意事项 |
---|---|---|---|
asin | double asin(double x); | 计算反正弦值,返回 x 的反正弦(以弧度表示),x 的范围是 [-1, 1] | 需要包含头文件 <math.h>,参数 x 必须在 [-1, 1] 范围内,否则结果未定义(可能返回 NaN)。 |
acos | double acos(double x); | 计算反余弦值,返回 x 的反余弦(以弧度表示),x 的范围是 [-1, 1] | 需要包含头文件 <math.h>,参数 x 必须在 [-1, 1] 范围内,否则结果未定义(可能返回 NaN)。 |
atan | double atan(double x); | 计算反正切值,返回 x 的反正切(以弧度表示) | 需要包含头文件 <math.h>,结果范围是 [-π/2, π/2]。 |
atan2 | double atan2(double y, double x); | 计算 y/x 的反正切值(以弧度表示),并根据 x 和 y 的符号确定正确的象限 | 需要包含头文件 <math.h>,能正确处理 x 为 0 的情况,结果范围是 [-π, π]。 |
- 头文件依赖:所有反三角函数均需包含 <math.h> 头文件,这是调用这些函数的前提条件,缺少该头文件会导致编译错误。
- 参数范围限制:
- asin 和 acos 函数的参数 x 必须在 [-1, 1] 范围内,否则结果未定义,编程时需确保参数在此范围内。
- atan 和 atan2 函数对参数范围没有严格限制,但 atan2 能更准确地处理坐标象限问题。
- 函数特性差异:
- atan 只能返回 [-π/2, π/2] 范围内的结果,无法区分坐标象限。
- atan2 通过两个参数 y 和 x 确定象限,结果范围是 [-π, π],在需要完整角度信息的场景中(如计算机图形学),atan2 是更优选择。
6.2 案例演示
#include <stdio.h>
#include <math.h> // 包含数学函数头文件
#define PI 3.14159265358979323846 // 定义 π 的近似值
int main()
{
double x = 0.5;
double y = 1.0;
// 计算并输出反正弦、反余弦和反正切值
printf("asin(%.2f) = %.6f radians\n", x, asin(x));
printf("acos(%.2f) = %.6f radians\n", x, acos(x));
printf("atan(%.2f) = %.6f radians\n", x, atan(x));
printf("atan2(%.2f, %.2f) = %.6f radians\n", y, x, atan2(y, x));
return 0;
}
程序在 VS Code 中的运行结果如下所示:
7 双曲函数
7.1 函数概述
函数名 | 函数原型 | 功能描述 | 注意事项 |
---|---|---|---|
sinh | double sinh(double x); | 计算双曲正弦值 | 需要包含头文件 <math.h>,参数 x 可以是任意实数。 |
cosh | double cosh(double x); | 计算双曲余弦值 | 需要包含头文件 <math.h>,参数 x 可以是任意实数。 |
tanh | double tanh(double x); | 计算双曲正切值 | 需要包含头文件 <math.h>,参数 x 可以是任意实数,结果范围是 (-1, 1)。 |
- 头文件依赖:所有双曲函数均需包含 <math.h> 头文件,这是调用这些函数的前提条件,缺少该头文件会导致编译错误。
- 参数范围:双曲函数的参数 x 可以是任意实数,没有特殊限制,但在编程时需注意数值过大可能导致溢出问题。
- 结果特性:
- sinh 和 cosh 的结果可以非常大,尤其是当 x 的绝对值较大时,可能导致数值溢出。
- tanh 的结果范围是 (-1, 1),适用于需要限制输出范围的场景,如激活函数。
7.2 案例演示
#include <stdio.h>
#include <math.h> // 包含数学函数头文件
int main()
{
double x = 1.0;
// 计算并输出双曲正弦、双曲余弦和双曲正切值
printf("sinh(%.2f) = %.6f\n", x, sinh(x));
printf("cosh(%.2f) = %.6f\n", x, cosh(x));
printf("tanh(%.2f) = %.6f\n", x, tanh(x));
return 0;
}
程序在 VS Code 中的运行结果如下所示:
8 <math.h> 中常见宏定义常量
8.1 常见宏定义常量
在 C 语言的 <math.h> 头文件中,定义了一系列常用的数学常量宏,这些宏提供了高精度的数学常数,方便开发者在程序中使用。
以下是这些宏定义常量的详细说明:
宏定义常量 | 值 | 描述 |
---|---|---|
M_E | 2.7182818284590452354 | 自然对数的底数 e,即 e ≈ 2.71828。在指数函数、对数函数等计算中频繁使用。 |
M_LOG2E | 1.4426950408889634074 | 以 2 为底的自然对数 e 的对数,即 log2e。用于二进制与自然对数之间的转换。 |
M_LOG10E | 0.43429448190325182765 | 以 10 为底的自然对数 e 的对数,即 log10e。用于十进制与自然对数之间的转换。 |
M_LN2 | 0.69314718055994530942 | 自然对数 ln(2)。在涉及 2 的幂次或对数计算中常用。 |
M_LN10 | 2.30258509299404568402 | 自然对数 ln(10)。在涉及 10 的幂次或对数计算中常用。 |
M_PI | 3.14159265358979323846 | 圆周率 π,即 π ≈ 3.14159。在几何、三角函数等计算中广泛使用。 |
M_PI_2 | 1.57079632679489661923 | π 的一半,即 π/2。常用于角度转换或半圆计算。 |
M_PI_4 | 0.78539816339744830962 | π 的四分之一,即 π/4。常用于 45 度角或四分之一圆计算。 |
M_1_PI | 0.31830988618379067154 | π 的倒数,即 1/π。在涉及 π 的倒数计算中常用。 |
M_2_PI | 0.63661977236758134308 | 2 倍的 π 的倒数,即 2/π。在涉及 π 的倒数且需要乘以 2 的计算中常用。 |
M_2_SQRTPI | 1.12837916709551257390 | 2 除以 π 的平方根,即 2/根号 π。在涉及 π 的平方根倒数且需要乘以 2 的计算中常用。 |
M_SQRT2 | 1.41421356237309504880 | 根号 2。在涉及 2 的平方根计算中常用。 |
M_SQRT1_2 | 0.70710678118654752440 | 1/根号 2。在涉及 2 的平方根倒数计算中常用。 |
宏定义的可移植性:虽然这些宏在大多数支持 C 标准的编译器中都是可用的,但它们的可用性可能依赖于具体的编译器和标准库实现。在某些平台上,可能需要定义 _USE_MATH_DEFINES 宏(通常在包含 <math.h> 之前定义)才能使用这些常量。
精度问题:这些宏定义的常量通常具有较高的精度,但在进行浮点数运算时,仍需注意浮点数的精度限制和舍入误差。
8.2 案例演示
#include <stdio.h>
#include <math.h> // 包含数学函数和宏定义头文件
#define _USE_MATH_DEFINES // 在某些编译器中需要定义此宏以启用数学常量
int main()
{
// 输出一些常见的数学常量
printf("M_E = %.20f\n", M_E); // 自然对数的底数 e
printf("M_LN2 = %.20f\n", M_LN2); // 2 的自然对数
printf("M_LN10 = %.20f\n", M_LN10); // 10 的自然对数
printf("M_PI = %.20f\n", M_PI); // 圆周率 π
printf("M_PI_2 = %.20f\n", M_PI_2); // π/2
printf("M_PI_4 = %.20f\n", M_PI_4); // π/4
printf("M_1_PI = %.20f\n", M_1_PI); // 1/π
printf("M_2_PI = %.20f\n", M_2_PI); // 2/π
printf("M_SQRT2 = %.20f\n", M_SQRT2); // 2 的平方根
return 0;
}
程序在 VS Code 中的运行结果如下所示: