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

来源:互联网 发布:在香港用淘宝 编辑:程序博客网 时间:2024/06/06 07:16

说明:

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

学习目标:


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

MSDN相关内容

代码实现:

窗体设计:

控件 个数 作用 textBox1 1个 输入没有乘以Pi的分子 textBox2 1个 输入没有乘以Pi的分母 label1 1个 显示sin(x)的结果 label2 1个 显示cos(x)的结果 textBox3 1个 用来测试用

上面的控件只是在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";            //}        }    }}

坑:

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

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

  2. 那段缩小范围的代码可能由冗余的,我暂时没有更好的解决方法。

0 0
原创粉丝点击