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

发布于:2025-06-15 ⋅ 阅读:(16) ⋅ 点赞:(0)

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 的对数,即 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 案例演示

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


网站公告

今日签到

点亮在社区的每一天
去签到