Arduino - 数学库
Arduino - 数学库
Section titled “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_PI | 3.14159265 | 圆周率 (π) 常量。 |
M_E | 2.71828182 | 常量 e,自然对数的底。 |
M_SQRT2 | 1.41421356 | 2 的平方根。 |
M_LN2 | 0.69314718 | 2 的自然对数。 |
M_LN10 | 2.30258509 | 10 的自然对数。 |
核心数学函数
Section titled “核心数学函数”以下是该库中最常用函数的精选列表。请注意,三角函数始终以弧度为单位进行操作,而不是角度。
| 函数签名 | 描述 |
|---|---|
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.00Angle (radians): 1.0472Sine of angle: 0.8660Cosine of angle: 0.50004.00 raised to the power of 3.00 is: 64.00The square root of 81.00 is: 9.00Rounding -3.70 floor(): -4.00 ceil(): -3.00 round(): -4.00最佳实践与调试
Section titled “最佳实践与调试”- 弧度,而非角度:这是最常见的错误。在使用
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 位小数的精度。如果你的计算正在累积微小误差,最终结果可能不准确。请注意这个限制。