c/c++ 实现三角函数(不使用库函数) sin/cos/tan/cot
简介
在许多嵌入式系统或计算平台中,可能不方便使用标准数学库函数。在本篇博客中,我们将使用 泰勒展开 来实现常见的三角函数:sin(x)、cos(x)、tan(x) 和 cot(x),而不依赖任何库函数。通过手动实现这些数学公式,我们可以更好地理解三角函数的计算原理,同时为那些受限的环境提供一种实现方案。
泰勒展开简介
泰勒展开是数学中一个非常重要的公式,它能够将任何在某点可导的函数展开为一个无限级数。对于三角函数,我们可以利用其在0点的泰勒级数展开来近似计算函数值。以 sin(x) 为例,它的泰勒展开式为:
s
i
n
(
x
)
=
x
−
x
3
3
!
+
x
5
5
!
−
x
7
7
!
+
.
.
.
sin(x)=x-\frac {x^3}{3!} + \frac {x^5}{5!} - \frac {x^7}{7!} + ...
sin(x)=x−3!x3+5!x5−7!x7+...
这意味着通过不断累加各阶项,可以近似计算出 s i n ( x ) sin(x) sin(x) 的值。每增加一项,结果会更加精确。
收敛性:
泰勒级数在某些情况下会收敛得非常快(如 x 接近 0 时)。然而,当 x 值较大时,收敛速度会减慢,需要更多项才能达到理想的精度。因此,在实现时我们设置了精度阈值 1e-15,当项的绝对值小于该值时,停止计算。
代码实现
#include <iostream>
#include <cstdlib>
#include <iomanip>
constexpr auto PI = 3.1415926;
// 显示菜单并选择操作
int menu_select() {
int select;
std::cout << "-------Welcome to Snow Calculator-------" << std::endl;
std::cout << " 1. sin x " << std::endl;
std::cout << " 2. cos x " << std::endl;
std::cout << " 3. tan x " << std::endl;
std::cout << " 4. cot x " << std::endl;
std::cout << " 5. Clean screen " << std::endl;
std::cout << " 0. to quit " << std::endl;
std::cout << "----------------------------------------" << std::endl;
std::cin >> select;
return select;
}
// 输入角度,并将角度转换为弧度
double inputtrans(void) {
double x;
while (true) {
std::cout << "Please input x (angle in degrees): ";
std::cin >> x;
if (std::cin.fail()) { // 输入非法时
std::cin.clear(); // 清除输入错误标志
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cout << "Invalid input. Please try again." << std::endl;
continue;
}
if (x >= 360) {
x -= 360.0; // 把角度归一化
}
break;
}
return (x * PI / 180.0); // 将角度转换为弧度
}
// 计算阶乘(迭代版本,避免递归栈溢出)
double factorial(int n) {
double result = 1;
for (int i = 1; i <= n; ++i) {
result *= i;
}
return result;
}
// 计算绝对值
double myabs(double num1) {
return((num1 > 0) ? num1 : -num1);
}
// 使用泰勒展开计算sin(x)
double snowsin(double x) {
double result = 0.0;
double term = x; // 初始化为 x^1 / 1!
int n = 1;
while (myabs(term) > 1e-15) { // 直到当前项小于精度要求
result += term;
term = -term * x * x / ((2 * n) * (2 * n + 1)); // 更新项
++n;
}
return result;
}
// 使用泰勒展开计算cos(x),通过 sin(PI/2 - x) 来优化
double snowcos(double x) {
x = (PI / 2) - x; // cos(x) = sin(PI/2 - x)
return snowsin(x);
}
// 使用sin(x) 和 cos(x) 计算tan(x)
double snowtan(double x) {
return (snowsin(x) / snowcos(x));
}
// 使用tan(x) 计算cot(x)
double snowcot(double x) {
return (1 / snowtan(x));
}
int main() {
double result = 0.0;
double x = 0.0;
int menu = menu_select();
while (menu != 0) {
switch (menu) {
case 1:
x = inputtrans();
result = snowsin(x);
std::cout << std::fixed << std::setprecision(5) << "Result = " << result << std::endl;
break;
case 2:
x = inputtrans();
result = snowcos(x);
std::cout << std::fixed << std::setprecision(5) << "Result = " << result << std::endl;
break;
case 3:
x = inputtrans();
result = snowtan(x);
std::cout << std::fixed << std::setprecision(5) << "Result = " << result << std::endl;
break;
case 4:
x = inputtrans();
result = snowcot(x);
std::cout << std::fixed << std::setprecision(5) << "Result = " << result << std::endl;
break;
case 5:
system("cls");
break;
case 0:
break;
default:
std::cout << "Wrong input, please input again!" << std::endl;
break;
}
if (menu == 0) {
break;
}
menu = menu_select();
}
std::cout << "Thank you for using!\nPress any key to exit.\n";
system("pause");
}
代码解释
- 输入和输出: 用户输入角度(以度为单位),程序会将角度转换为弧度并计算相应的三角函数值。
- 泰勒展开: 使用泰勒展开计算 sin(x)、cos(x)、tan(x) 和 cot(x)。对于 sin(x) 和 cos(x),通过反复累加展开项,直到当前项的绝对值小于 1e-15 时停止计算。
- 阶乘计算: 使用迭代方式计算阶乘,避免递归深度过深导致栈溢出。
常见问题与改进建议
-
精度问题:
由于使用的是泰勒展开,随着计算项数的增加,计算的精度会逐渐提高,但对较大角度的计算可能存在一定误差。可以通过将角度 x x x转换到 [ − π , π ] [-π, π] [−π,π]范围内来提高精度。 -
优化:
当前的snowsin和snowcos计算方式较为低效,可以通过利用一些三角恒等式来优化。例如:
c o s ( x ) = s i n ( π 2 − x ) cos(x)=sin(\frac{π}{2}-x) cos(x)=sin(2π−x)
这种优化可以避免不必要的计算,提高程序效率。
总结
通过不使用标准库,直接使用泰勒展开来实现三角函数的计算,不仅加深了对数学公式的理解,也为特定需求下的低资源环境提供了一种有效的计算方法。尽管该方法在某些情况下可能精度不高,但在学习和嵌入式计算中仍然具有很高的价值。
更多推荐
所有评论(0)