求向量的欧拉范数

求向量的欧拉范数

       求欧拉范数是一个比较简单的算法,似乎没有什么可说的,一般代码如下:
/* * \fn double enorm1(long n, const double* x)
* \brief 求欧拉范数,简单算法。
* \param [in] n 向量长度
* \param [in] x 向量值 
* \return 欧拉范数
*/
double  enorm1( long  n,  const   double *  x)
{
    
double  ret  =   0.0 ;
    
long  i  =   0 ;
    
for  (i = 0 ; i < n;  ++ i)
        ret 
+=  x[i] * x[i];
        
    
return  sqrt(ret);
}

然而近日在学习minpack时,发现它求欧拉范数的函数enorm则要复杂得多。仔细比较发现上面算法有不足,它没有考虑溢出的情况,当x[i]为很小或者很大的数时,x[i]*x[i]则会下溢或者上溢,最后结果可能不准确。但x[i]*x[i]只是中间结果,最后的范数数量级应该和x[i]相同。它溢出的可能性要小得多。改进中间结果则可以改进算法。

/* * \fn double enorm2(long n, const double* x)
* \brief 求欧拉范数,考虑溢出的算法。
* \param [in] n 向量长度
* \param [in] x 向量值 
* \return 欧拉范数
*/
double  enorm2( long  n,  const   double   * x)
{
    
double  ret  =   0.0 ;
    
long  i =   0 ;
    
double  xmax  =   0.0 ;
    
    
for  (i = 0 ; i < n;  ++ i)
    {
        
double  xabs  =  fabs(x[i]);
        
        
/*  这个比较方式不需要考虑xabs和xmax为0的情况  */
        
if  (xabs  <  xmax)
        {
            ret 
+=  (xabs / xmax) * (xabs / xmax);
        }
        
else   if  (xabs  ==  xmax)  
        {
            ret 
+=   1 ;
        }
        
else
        {
            ret 
=   1   +  ret * (xmax / xabs) * (xmax / xabs);
            xmax 
=  xabs;
        }
    }
    
return  sqrt(ret)  *  xmax;
}

   将中间结果改成(x[i]/xmax)*(x[i]/xmax),降低了溢出的可能。当然该算法没有区分可能溢出和不溢出的数,计算量较大。下面的算法是仿照minpack的enorm函数编写:

/* * \fn double enorm3(long n, const double* x)
* \brief 求欧拉范数,仿照minpack的enorm函数
* \param [in] n 向量长度
* \param [in] x 向量值 
* \return 欧拉范数
*/
double  enorm3( long  n,  const   double   * x)
{
    
double  s1  =   0.0 ;    
    
double  s2  =   0.0 ;    
    
double  s3  =   0.0 ;    
    
    
/*  上溢和下溢的边界,不一定要十分精确  */
    
const   double  dwarf  =   1.483e-154 ;     /*  下溢的边界  */
    
const   double  giant  =   1.341e154   /  n;  /*  上溢的边界  */
    
    
double  x1max  =   0.0
    
double  x3max  =   0.0
    
    
long  i  =   0 ;
    
for  (i = 0 ; i < n;  ++ i)
    {
        
double  xabs  =  fabs(x[i]);
        
        
if  (xabs  >  dwarf  &&  xabs  <  giant)
        {
            s2 
+=  xabs * xabs;
        }
        
else   if  (xabs  <=  dwarf)
        {
            
/*  这个比较方式不需要考虑xabs和xmax为0的情况  */
            
if  (xabs  <  x3max)
            {
                s3 
+=  (xabs / x3max) * (xabs / x3max);
            }
            
else   if  (xabs  ==  x3max)
            {
                s3 
+=   1 ;
            }
            
else
            {
                s3 
= 1   +  s3 * (x3max / xabs) * (x3max / xabs);
                x3max 
=  xabs;
            }
        }
        
else   /*  if (xabs >= giant)  */
        {
            
/*  不需要考虑xabs和xmax为0的情况  */
            
if  (xabs  <=  x1max)
            {
                s1 
+=  (xabs / x1max) * (xabs / x1max);
            }
            
else   if  (xabs  ==  x1max)
            {
                s1 
+=   1 ;
            }
            
else
            {
                s1 
= 1   +  s1 * (x1max / xabs) * (x1max / xabs);
                x1max 
=  xabs;
            }
        }
    }
    
    
if  (s1  !=   0.0 )
    {
        
return  x1max * sqrt(s1  +  s2 / x1max / x1max);
    }
    
else   if  (s2  !=   0.0 )
    {
        
return  sqrt(s2  +  x3max * x3max * s3);
        
/*  下面为minpack中enorm的代码,好像没有必要 
        if (s2 >= x3max)
            return sqrt(s2 * (1 + x3max/s2*x3max*s3));
        else
            return sqrt(x3max * (s2/x3max + x3max*s2));
        
*/
    }
    
else
    {
        
return  x3max  *  sqrt(s3);
    }
}

 

下面是测试结果:

 

<td style="BORDER-RIGHT: rgb(0,0,0) 0.5pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0pt; BO

向量

enorm1

enorm2

enorm3

{1, 2, 3}

3.74166

3.74166

3.74166

{1e200, 2e200, 3e200}

1.#INF

导航

  • C++博客
  • 首页
  • 新随笔
  • 联系
  • RSS 2.0 Feed聚合
  • 管理
< 2007年9月 >
26 27 28 29 30 31 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 1 2 3 4 5 6

常用链接

  • 我的随笔
  • 我的评论
  • 我参与的随笔

留言簿(4)

  • 给我留言
  • 查看公开留言
  • 查看私人留言

随笔档案

  • 2016年1月 (1)
  • 2015年12月 (1)
  • 2015年11月 (2)
  • 2015年9月 (1)
  • 2015年8月 (2)
  • 2015年3月 (1)
  • 2015年1月 (1)
  • 2014年12月 (3)
  • 2014年6月 (2)
  • 2014年5月 (2)
  • 2012年8月 (1)
  • 2011年12月 (1)
  • 2011年6月 (1)
  • 2011年1月 (1)
  • 2010年8月 (1)
  • 2009年8月 (1)
  • 2009年5月 (1)
  • 2008年6月 (1)
  • 2008年5月 (1)
  • 2008年3月 (4)
  • 2008年1月 (5)
  • 2007年12月 (1)
  • 2007年11月 (4)
  • 2007年10月 (1)
  • 2007年9月 (1)

搜索

  •  

最新随笔

  • 1. 倒数1、2的票数相同的概率
  • 2. 技巧——拖拽执行BAT文件
  • 3. 影响SQLite3速度的方法
  • 4. 如何在自动测试中模拟设备在案例中的行为
  • 5. TortoiseSVN的两个Properties功能
  • 6. 等待子窗口创建完成的阻塞问题
  • 7. 注意printf类函数的format参数
  • 8. 内联单件模式的获取实例函数在VC6 Max-Speed选项下的错误
  • 9. 日志库优化——根据变化频率分类记录
  • 10. 工艺——使用辅助类表示构建函数的参数

最新评论

  • 1. re: 智力题:5个强盗分100个金币
  • 试一下不登陆可不可以评论
  • --xxoo
  • 2. re: VS2010调试断点不起作用的解决方法[未登录]
  • 刚都可以不知动了那里,就出现断点不能调试了。
    编译都是正确的。问题出在那里呢。
  • --liu
  • 3. re: 计算24点[未登录]
  • 评论内容较长,点击标题查看
  • --lemene
  • 4. re: 计算24点
  • 评论内容较长,点击标题查看
  • --jjx
  • 5. re: VS2005调试断点不起作用的解决方法
  • 评论内容较长,点击标题查看
  • --孙磊磊

阅读排行榜

  • 1. VS2005调试断点不起作用的解决方法(6888)
  • 2. 猜数字的一种解法(3453)
  • 3. 智力题:5个强盗分100个金币(3214)
  • 4. 拼图游戏(2268)
  • 5. 简易统计程序运行时间的程序(1884)

评论排行榜

  • 1. VS2005调试断点不起作用的解决方法(10)
  • 2. 智力题:5个强盗分100个金币(10)
  • 3. 拼图游戏(6)
  • 4. 猜数字的一种解法(5)
  • 5. 三选一(3)

你可能感兴趣的:(求向量的欧拉范数)