43 C 语言 math.h 库函数详解:绝对值、数学运算、取整舍入、分解组合、三角反三角、双曲函数及宏定义常量

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 案例演示

cpp 复制代码
#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 案例演示

cpp 复制代码
#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 案例演示

cpp 复制代码
#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 案例演示

cpp 复制代码
#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 案例演示

cpp 复制代码
#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 案例演示

cpp 复制代码
#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 案例演示

cpp 复制代码
#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 的对数,即 log2​e。用于二进制与自然对数之间的转换。
M_LOG10E 0.43429448190325182765 以 10 为底的自然对数 e 的对数,即 log10​e。用于十进制与自然对数之间的转换。
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 案例演示

cpp 复制代码
#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 中的运行结果如下所示:

相关推荐
IOT那些事儿5 天前
DSP使用三角函数问题
dsp·三角函数·sinf
功夫熊猫大侠11 天前
几何绘图与三角函数计算应用
三角函数·几何绘图
巽星石8 个月前
【Blender Python】7.一些运算、三角函数以及随机
python·blender·三角函数·随机·环形阵列
临床数据科学和人工智能兴趣组10 个月前
用R语言进行绝对值运算、平方根运算和三角函数运算
数据挖掘·数据分析·r语言·r·三角函数·运算
荒原之梦网10 个月前
【考研高数】tan(arcsin x)、tan(arccos x)、sin(arccos x)、cos(arcsin x) 等于多少?
考研·考研数学·三角函数
LaoZhangGong1232 年前
傅里叶级数系数的完整详细算法
经验分享·算法·高等数学·滤波·三角函数·傅里叶级数·积分
xuchaoxin13752 年前
EM@三角恒等变换P1
三角函数