您的位置:首页 > 其它

学习:实现任意角度的sin、cos求值-No.2

2016-10-28 18:35 681 查看

说明:

已经实现了特殊角的求值,圆周角还是使用原来的数值,能够保证每次的结果至少在小数点后10位的准确性.

学习目标:

使用
Math.Round
来确定
double
类型的保留小数点位数

MSDN相关内容

代码实现:

窗体设计:

控件个数作用
textBox11个输入没有乘以Pi的分子
textBox21个输入没有乘以Pi的分母
label11个显示sin(x)的结果
label21个显示cos(x)的结果
textBox31个用来测试用
上面的控件只是在C#的窗体设计中使用的,关于计算sin、cos的算法是一致的。

namespace Taylor
{
public partial class Form1 : Form
{
double Pi = 3.14159265358979;
double x;

public Form1()
{
InitializeComponent();
textBox1.Focus();
//textBox3用来测试用
//textBox3.Visible = false;
}

public double sin(double x)
{
double sin_x = 0.0;
int symbol = 1;

if (x < 0 || x > Pi / 2.0)
{
//缩小角度范围为[0, 正无穷)
//sin(-a) = -sin(a)
if (x < 0)
{
symbol *= -1;
x *= -1;
}

//缩小角度范围为[0, 2PI)
//sin(a + 2kPi) = sin(a)
if ((int)(x / (2 * Pi)) != 0)
x = x - (int)(x / (2 * Pi)) * (2 * Pi);

//缩小角度范围为[0, 3 * Pi / 2)
//sin(a + 3 * Pi / 2) = -cos(a)
if ((int)(x / (3 * Pi / 2.0)) != 0)
{
symbol *= -1;
return symbol * cos(x - (int)(x / (3 * Pi / 2.0)) * (3 * Pi / 2.0));
}

//缩小角度范围为[0, Pi)
//sin(a + Pi) = -sin(a)
if ((int)(x / Pi) != 0)
{
x = x - (int)(x / Pi) * Pi;
symbol *= -1;
}

//缩小角度范围为[0, Pi / 2)
//sin(a + Pi / 2) = cos(a)
if ((int)(x / (Pi / 2.0)) != 0)
{
return symbol * cos(x - (int)(x / (Pi / 2.0)) * Pi / 2.0);
}
}

//这里判断使用Math.Round(double value, int digits)格式化double类型保留指定小数位
if (Math.Round(x, 10) == 0.0)
return 0;
else if (Math.Round(x, 10) == Math.Round(Pi / 6.0, 10))
return symbol * 0.5;
else if (Math.Round(x, 10) == Math.Round(Pi / 2.0, 10))
return symbol * 1;
else
{
for (int n = 0; n < 10; n++) //取前十次的项来计算
{
double a = 1.0, b = 1.0, c = 1.0;

//计算(-1)的(n)次方
for (int i = 0; i < n; i++)
{
a *= -1;
}

//计算(2n + 1)的阶乘
for (int i = 1; i <= 2 * n + 1; i++)
{
b *= i;
}

//计算(x)的(2n+1)次方
for (int i = 0; i < 2 * n + 1; i++)
{
c *= x;
}

sin_x += ((a / b) * c);
}

return symbol * sin_x;
}
}

public double cos(double x)
{
double cos_x = 0.0;
int symbol = 1;

if (x < 0 || x > Pi / 2.0)
{
//缩小角度范围为[0, 正无穷)
//cos(-a) = cos(a)
if (x < 0)
{
x *= -1;
}

//缩小角度范围为[0, 2PI)
//cos(a + 2kPi) = cos(a)
if ((int)(x / (2 * Pi)) != 0)
x = x - (int)(x / (2 * Pi)) * (2 * Pi);

//缩小角度范围为[0, 3 * Pi / 2)
//cos(a + 3 * Pi / 2) = sin(a)
if ((int)(x / (3 * Pi / 2.0)) != 0)
{
return symbol * sin(x - (int)(x / (3 * Pi / 2.0)) * (3 * Pi / 2.0));
}

//缩小角度范围为[0, Pi)
//cos(a + Pi) = -cos(a)
if ((int)(x / Pi) != 0)
{
symbol *= -1;
x = x - (int)(x / Pi) * Pi;
}

//缩小角度范围为[0, Pi / 2)
//cos(a + Pi / 2) = -sin(a)
if ((int)(x / (Pi / 2.0)) != 0)
{
symbol *= -1;
return symbol * sin(x - (int)(x / (Pi / 2.0)) * Pi / 2.0);
}
}

if (Math.Round(x, 10) == 0.0)
return symbol * 1;
else if (Math.Round(x, 10) == Math.Round(Pi / 3.0, 10))
return symbol * 0.5;
else if (Math.Round(x, 10) == Math.Round(Pi / 2.0, 10))
return 0;
else
{
for (int n = 0; n < 10; n++) //取前十次的项来计算
{
double a = 1.0, b = 1.0, c = 1.0;

//计算(-1)的(n)次方
for (int i = 0; i < n; i++)
{
a *= -1;
}

//计算(2n)的阶乘
for (int i = 1; i <= 2 * n; i++)
{
b *= i;
}

//计算(x)的(2n+1)次方
for (int i = 0; i < 2 * n; i++)
{
c *= x;
}

cos_x += a * c / b;
}

return symbol * cos_x;
}
}

private void button1_Click(object sender, EventArgs e)
{
x = Convert.ToDouble(textBox1.Text) / Convert.ToDouble(textBox2.Text) * Pi;

label1.Text = "sinx = " + sin(x).ToString();
label2.Text = "cosx = " + cos(x).ToString();

textBox1.Focus();

//测试用
//textBox3.Visible = true;
//for (double m = 0.0; m < 10; m++)
//{
//    for (double n = 1.0; n < m; n++)
//    {
//        x = m / n * Pi;
//        textBox3.Text += m + "/" + n + " Pi:" + cos(x).ToString() + "\r\n";
//    }

//    textBox3.Text += "\r\n";
//}
}
}
}


坑:

使用泰勒展开式计算特殊角得出的结果不是特殊角对应的结果,而是一个无限无限接近的值,这个时候使用
if (x == 0.0)
这种来判等的话就不能判等正确了,所以就使用了
Math.Round
来缩小范围。

由上得,能使用整型的时候不要使用浮点型,用了浮点型就尽量不要用来计算,要计算的时候就要特别注意啦!

那段缩小范围的代码可能由冗余的,我暂时没有更好的解决方法。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: