| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 3786 人关注过本帖
标题:关于数学题arcsinx的求解
只看楼主 加入收藏
baobaoisme
Rank: 7Rank: 7Rank: 7
来 自:AVATAR
等 级:黑侠
帖 子:260
专家分:506
注 册:2010-7-9
结帖率:100%
收藏
已结贴  问题点数:10 回复次数:6 
关于数学题arcsinx的求解
前两天发了帖子获取思路,Amy_huyier网友回帖给予了好几个解法,我前天试了试,但是用二分法在迭代过程出现了一些问题
刚刚我使用另外一种定积分定义进行了运算,成功得到了arcsinx的结果,误差基于在进行分割0到x区间的n值的大小,我选择n=10000000,误差缩小到了1e-4,
求解平方根的迭代不需要太大,我一开始设置很大,发觉没必要并且机器已经反应不过来。。。。。。cpu利用率疯狂飙升
后来经过调试n=10就可以把平方根精确到大约1e-6次方的精度了。(囧了。。。刚才改了一下,其实只要迭代10次精度都可以达到很高要求。。。)
现在发觉高数还真没白学。。。大家一起好好学各种数学哇~~~~~
下面紧跟是成功用定积分定义求出的arcsinx,在下面一贴是我前几天失败的案例,希望大家有时间帮我看看哪里出了问题,非常感谢
程序代码:
#include <stdio.h>
#include <math.h>

int main()
{
    double sqr(double a);
    double arcsin(double x);
    double x;
    scanf("%lf",&x);
    printf("mine arcsinx = %lf\n\"math.h\"asinx = %lf\n",arcsin(x),asin(x));
    return 0;
}
double sqr(double a)//迭代法求根号a
{
    double y=a;
    long n=10;//改为10
    do
    {
    y = (y+a/y)/2;
    n--;
    }while(n>0);
    return y;
}
double inside(long i,long n,double x)
{
    return 1/sqr(1-(i*x/n)*(i*x/n));
}
double arcsin(double x)//使用积分定义算1/sqtr(1-x*x)的积分,积分下限为0,上限为x,积分完成后返回arcsinx的值
{
    double result=0;
    long i=0,n=10000000;//0到x的区间分成n份
    double outside=x/n;
    while(i<n)
    {
        result += outside*inside(i,n,x);
        i++;
    }
    return result;
}



[ 本帖最后由 baobaoisme 于 2011-2-28 20:10 编辑 ]
搜索更多相关主题的帖子: 数学题 二分法 平方根 
2011-02-28 20:01
baobaoisme
Rank: 7Rank: 7Rank: 7
来 自:AVATAR
等 级:黑侠
帖 子:260
专家分:506
注 册:2010-7-9
收藏
得分:0 
失败的案例
程序代码:
#include <stdio.h>
#include <math.h>

int fact(int);
double xn(double,int);
double Sin(double);
double f(double,double);
double arcsin(double,double,double);
int main()
{
    double x,a,b;
    printf("请输入arcsinx中所要求的x的值:\n");
    scanf("%lf",&x);
    printf("请输入符合条件的a与b的值:\n");
    scanf("%lf%lf",&a,&b);
    while (f(a,x)*f(b,x)>0)
    {
        printf("不符合条件,请重新输入a与b的值:\n");
        scanf("%lf%lf",&a,&b);
    }
    printf("%lf %lf",arcsin(a,b,x),asin(x));
    return 0;
}
double arcsin(double a,double b,double x)//返回arcsinx的值,即返回使f(y)=0方程的解
{
    double c=(a+b)/2.0;
    while (fabs(a-b)>1e-8)//二分法求根,精度设置
    {
        if (f(c,x)*f(a,x)>1e-6)
            a=c;
        else
            b=c;
        c=(a+b)/2.0;
    }
    printf("f(y)=%lf\n",f(c,x));
    return c;
}
double f(double y,double x)//求解函数f(y)=siny-x
{
    return Sin(y)-x;
}
double Sin(double x)//级数展开sinx
{
    int flag=1;
    double result=0;
    int n=0;
    while ( (xn(x,2*n+1)/fact(2*n+1)) > 1e-6 )//精度设置
    {
        result += (xn(x,2*n+1)/fact(2*n+1))*flag;
        flag=-flag;
        n++;
    }
    return result;
}
double xn(double x,int n)//求x的n次方
{
    while (n>1)
    {
        x=x*x;
        n--;
    }
    return x;
}
int fact(int n)//求阶乘
{
    int result=1;
    while (n>0)
    {
        result *= n;
        n--;
    }
    return result;
}

2011-02-28 20:02
pangding
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:北京
等 级:贵宾
威 望:94
帖 子:6784
专家分:16751
注 册:2008-12-20
收藏
得分:10 
要想写够快的函数,就不能用循环。要求函数能在常数时间内返回。
我以前专门研究过一段时间数学函数的数值算法。不过现在忘了不少。我只能说一下思路,其它的得自己查资料。

凡是这类算法,都要用有“微分学顶峰”称号的泰勒公式(马克劳林公式)。
但一般人都知道,这个公式有个缺点,就是在 0 点附近有极好的精度,一远了就不行了。
所以数值算法的任务就想各种办法把 x “拉”到 0 点附近,再加以施用。如果拉的够近,往往发现只用算前5,7项,誤差就能控制在 double 能表示的最小精度范围内。循环算更多项,往往比“拉”过来更费时间。所以提前处理一下就显得非常值得了。(这和你发现求 sqrt 的这个道理差不多。因为牛顿切线在求二次方根时收敛的非常快,当然要写 sqrt 的数值算法,还有更适宜的。)
而拉好了之后具体算多少项才能达到精度,是能给出上限估计的,也就是说和 x 的值无关。那么这个函数就不用用循环,而是可以在常数时间内返回。

以上是通论,下面我可以介绍一下 arcsin 的求法。我查了一下我以前学习时的笔记,不过有的地方当时推了,现在忘了又懒得推。你要么听说一下就是了,要么就再自己查点资料。
由asin(x) 的奇偶性,就知道只用求 [0, 1] 这个区间的就可以了。这个结论可以说是比较好了,由于定义域的原因,本来 x 就不会离原点太远。这和 sqrt 呀,sin 什么的就很不同。不过还是要“拉一拉”。用公式:
arcsin(x) = pi/2 - 2 * arcsin( sqrt [(1-x)/2] )

可以把求 [0.5, 1] 之间问题归结为求 [0, 0.5] 之间的问题。这就是把 x “拉”到了 [0, 0.5] 里。
另外,大家可能都知道 x~arcsin(x) (x 和 arcsin(x) 是等价无穷小量)。于是当 x 小于一个很小的数的时候,可以直接返回 x。

此时应用公式:
asin(x) = x + x^3/6 + x^5*3/40 + x^7*15/336 + ...

就可以估计余项的誤差了。但很可惜,我现在想不起来这个公式是怎么推的了(应该是得用一些技巧),从而误差分析也没法做了。
根据我以前的笔记,它只用算 5 项就可以达到精度(第一项是 x 不用算,之后还要算 5 项)。

分析到这差不多了。函数写完的样子大约是:(伪代码)
程序代码:
double Asin(double x)
{
    int sign = 1;
    if (x < 0) { x = -x; sign = -1; }

    if (x > 1) return /* NaN */;
    if (x < /* a very small number */ ) return x;

// of course you can compute all those constant before hacking.
#define PIO2 (3.1415... / 2.0)
#define P1 (1.0/0.6)
#define P2 ....
......
    if (x > 0.5) return PIO2 - 2*Asin( sqrt( (1-x)/2 ) );

    double x2 = x*x;
    return sign * (x + x*x2 * (p1 + x2*(p2 + x2*(p3 + x2*(p4 + x2*p5)))));
}

昨天最后那个多项式写的错误比较严重,希望没有误导太多人……
另外应该加上判断 x 不在定义域的情况。顺便改几个错别字。


[ 本帖最后由 pangding 于 2011-3-1 09:06 编辑 ]
2011-02-28 22:14
baobaoisme
Rank: 7Rank: 7Rank: 7
来 自:AVATAR
等 级:黑侠
帖 子:260
专家分:506
注 册:2010-7-9
收藏
得分:0 
回复 3楼 pangding
非常感谢,貌似研一还要开计算方法这门课,希望以后有机会好好学习一下。。。。。
2011-03-01 12:59
pangding
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:北京
等 级:贵宾
威 望:94
帖 子:6784
专家分:16751
注 册:2008-12-20
收藏
得分:0 
以下是引用baobaoisme在2011-3-1 12:59:41的发言:

非常感谢,貌似研一还要开计算方法这门课,希望以后有机会好好学习一下。。。。。

哦?你是今年考的研吗?什么专业?
2011-03-01 21:16
baobaoisme
Rank: 7Rank: 7Rank: 7
来 自:AVATAR
等 级:黑侠
帖 子:260
专家分:506
注 册:2010-7-9
收藏
得分:0 
回复 5楼 pangding
恩,我本科就是计算机科学与技术专业,考的也是本专业了
2011-03-01 22:08
pangding
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:北京
等 级:贵宾
威 望:94
帖 子:6784
专家分:16751
注 册:2008-12-20
收藏
得分:0 
呵呵,有潜力。我是学数学的。
2011-03-01 22:39
快速回复:关于数学题arcsinx的求解
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.042413 second(s), 7 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved