Skip to content

Arduino - 数学库

Arduino 环境基于 C++ 构建,包含了标准 C 数学库(math.h),该库提供了丰富的函数集合,用于执行浮点数运算。这对于传感器数据处理、动画、机器人技术等任务至关重要。

要使用这些函数,你通常需要在程序(sketch)的顶部包含该库:

#include <math.h>

虽然在 Arduino 工具链中,math.h 库通常默认被包含,但显式地包含它是一个为了代码清晰性和可移植性的良好实践。

理解 Arduino 上的 float 和 double 数据类型

Section titled “理解 Arduino 上的 float 和 double 数据类型”

对于 Arduino 开发者来说,一个关键点是:在许多经典的 Arduino 开发板(例如基于 AVR 架构的 Uno、Nano、Mega)上,double 数据类型被实现为 4 字节的浮点数,与 float 类型完全相同,不提供额外的精度。而在更强大的 32 位开发板(例如 Arduino Due、Zero 或基于 ESP32 的开发板)上,double 则提供 8 字节的双精度浮点数。在处理高精度计算时,请务必了解你的目标开发板的能力。

math.h 库定义了几个有用的数学常量。以下是最重要的几个:

常量近似值描述
M_PI3.14159265圆周率 (π) 常量。
M_E2.71828182常量 e,自然对数的底。
M_SQRT21.414213562 的平方根。
M_LN20.693147182 的自然对数。
M_LN102.3025850910 的自然对数。

以下是该库中最常用函数的精选列表。请注意,三角函数始终以弧度为单位进行操作,而不是角度。

函数签名描述
double sin(double x)计算 x 的正弦值,其中 x 以弧度为单位。
double cos(double x)计算 x 的余弦值,其中 x 以弧度为单位。
double tan(double x)计算 x 的正切值,其中 x 以弧度为单位。
double asin(double x)计算 x 的反正弦(反三角函数)。返回一个介于 -π/2 和 π/2 之间的弧度值。x 必须介于 -1 和 1 之间。
double acos(double x)计算 x 的反余弦(反三角函数)。返回一个介于 0 和 π 之间的弧度值。x 必须介于 -1 和 1 之间。
double atan2(double y, double x)计算 y/x 的反正切,使用两个参数的符号来确定正确的象限。返回一个介于 -π 和 π 之间的弧度值。这通常比 atan(y/x) 更安全。
double pow(double base, double exponent)计算 base 的 exponent 次幂。
double sqrt(double x)计算 x 的非负平方根。
double cbrt(double x)计算 x 的立方根。
double exp(double x)计算 e 的 x 次幂(e^x)。
double log(double x)计算 x 的自然对数(以 e 为底)。
double log10(double x)计算 x 的常用对数(以 10 为底)。
double fabs(double x)计算浮点数 x 的绝对值。
double floor(double x)将 x 向下舍入到最接近的整数(返回浮点数)。
double ceil(double x)将 x 向上舍入到最接近的整数(返回浮点数)。
double round(double x)将 x 舍入到最接近的整数,半数情况下(例如 X.5)远离零点舍入。
double fmod(double x, double y)计算 x / y 的浮点余数。
double hypot(double x, double y)稳健地计算 sqrt(xx + yy),避免中间过程的溢出或下溢。
int isnan(double x)如果 x 是非数字(NaN),则返回非零值,否则返回 0。
int isinf(double x)如果 x 是正无穷大则返回 1,负无穷大则返回 -1,否则返回 0。

关于 square() 的注意事项:Arduino 核心还提供了一个 square(x) 宏,它仅仅返回 x * x。虽然方便,但它不属于标准 C 数学库,并且由于其宏实现,可能会产生意外的副作用。直接使用 pow(x, 2) 或 x * x 通常更安全、更清晰。

这个示例演示了几个关键的数学函数。它将角度从度转换为弧度,计算三角函数值,并展示了 pow 和 sqrt 的用法。

// 包含数学库以提高代码清晰度
#include <math.h>
// 对于不变化的量使用 'const'。
const float angleDegrees = 60.0;
void setup() {
Serial.begin(9600);
while (!Serial); // 等待串口监视器连接
Serial.println("--- Arduino Math Library Demo ---");
// --- 三角函数 ---
// 三角函数需要以弧度为单位的角度。我们来转换一下。
float angleRadians = angleDegrees * (M_PI / 180.0);
Serial.print("Angle (degrees): ");
Serial.println(angleDegrees);
Serial.print("Angle (radians): ");
Serial.println(angleRadians, 4); // 打印小数点后 4 位
float sinValue = sin(angleRadians);
float cosValue = cos(angleRadians);
Serial.print("Sine of angle: ");
Serial.println(sinValue, 4);
Serial.print("Cosine of angle: ");
Serial.println(cosValue, 4);
// --- 幂和根 ---
float base = 4.0;
float exponent = 3.0; // 4 的 3 次方
float powerResult = pow(base, exponent);
Serial.print(base);
Serial.print(" raised to the power of ");
Serial.print(exponent);
Serial.print(" is: ");
Serial.println(powerResult);
float numberToRoot = 81.0;
float sqrtResult = sqrt(numberToRoot);
Serial.print("The square root of ");
Serial.print(numberToRoot);
Serial.print(" is: ");
Serial.println(sqrtResult);
// --- 舍入 ---
float valueToRound = -3.7;
Serial.print("Rounding ");
Serial.println(valueToRound);
Serial.print(" floor(): ");
Serial.println(floor(valueToRound));
Serial.print(" ceil(): ");
Serial.println(ceil(valueToRound));
Serial.print(" round(): ");
Serial.println(round(valueToRound));
}
void loop() {
// 对于这个示例,这里没有什么可做的
}
--- Arduino Math Library Demo ---
Angle (degrees): 60.00
Angle (radians): 1.0472
Sine of angle: 0.8660
Cosine of angle: 0.5000
4.00 raised to the power of 3.00 is: 64.00
The square root of 81.00 is: 9.00
Rounding -3.70
floor(): -4.00
ceil(): -3.00
round(): -4.00
  • 弧度,而非角度:这是最常见的错误。在使用 sin()、cos()、tan() 等函数之前,务必将角度转换为弧度(radians = degrees * M_PI / 180.0)。
  • 定义域错误:像 acos(x) 和 asin(x) 这样的函数只对 -1 到 1 之间的 x 有定义。log(x) 仅对 x > 0 有定义。提供一个超出范围的值将导致 NaN(非数字)。使用 isnan() 来检查此错误。
  • 性能:在大多数 Arduino 上,浮点数运算比整数运算慢得多。如果需要速度,请尽可能尝试使用整数重新构建问题。
  • 精度:float 大约有 6-7 位小数的精度。如果你的计算正在累积微小误差,最终结果可能不准确。请注意这个限制。