CSDN首页 空间 新闻 论坛 Blog 下载 读书 网摘 搜索 .NET Java 视频 接项目 求职 在线学习 买书 程序员 通知
不看会后悔的Windows XP之经验谈 简单快捷DIY实用家庭影院
CSDN社区
搜索 收藏 打印 关闭
CSDN社区 >  专题开发/技术/项目 >  数据结构与算法

请问如何快速计算出以二为底对数?该数在0到1之间,要求计算出的精度在小数点4位。谢谢

楼主FirstTime(第一次来)2005-09-06 09:26:03 在 专题开发/技术/项目 / 数据结构与算法 提问

谢谢。 问题点数:50、回复次数:9Top

1 楼happy__888([顾问团]寻开心 www.e-jjj.com)回复于 2005-09-06 10:02:47 得分 25

用展开公式逼近吧  
   
  ln(1-x)   =   -(x   +   x^2/2   +   x^3/3   +   x^4/4   ....)  
   
                        x-1       1       x-1               1       x-1  
  lnx   =   2*   (----   +   -   -------^3   +   -   --------^5   .........)  
                        x+1       3       x+1               5       x+1Top

2 楼liangbch(宝宝)回复于 2005-09-06 10:46:48 得分 25

从8byte   double   数中读出阶码k(k<0),再将此数   乘以   (2的-k次方)以转化为   1-2之间的数x1,然后就可以用上面的方法求出   ln(x1),则结果为   y=   k   +   ln(x1)/ln(2).Top

3 楼happy__888([顾问团]寻开心 www.e-jjj.com)回复于 2005-09-06 11:32:33 得分 0

 
  换个办法吧:  
  对于在0到1区间的   x,   令   y=1/x    
  我们计算出   log   y来,   显然   log   x   =   -   log   y  
   
  y的范围是   1   到   正无穷  
  浮点数在计算机当中的表述方式就是:  
          y   =   1.m     *   2^n  
  可以根据浮点数的内存结构,直接提出出来   n的数值  
          log   y   =   n   +   log   1.m    
  提取出来n后,我们直接操作浮点数,把它规范化到1.m的格式  
  然后对于1到2区间的数值,建立一个跨度为0.0001的查询表  
  通过查询计算出   log1.m的数值  
   
   
  关于浮点数的内存结构可以从我的blog当中获取:   blog.csdn.net/happy__888  
   
  jiejueTop

4 楼liangbch(宝宝)回复于 2005-09-06 15:09:17 得分 0

下面给出完整的程序:  
   
  #include   "stdlib.h"  
  #include   "stdio.h"  
   
  typedef   unsigned   short   WORD;  
  #define   LOG2E       1.4426950408889634073599246810019   //log2(e)  
  short   GetExpBase2(double   a)   //   获得   a   的阶码  
  {  
          //   按照IEEE   754浮点数格式,取得阶码,仅仅适用于Intel   系列   cpu    
          WORD   *pWord=(WORD   *)(&a)+3;  
          return     (   (*pWord   &   0x7fff)   >>4   )-0x3ff;  
  }  
   
  double   GetMantissa(double   a)   //   获得   a   的   尾数  
  {  
          //   按照IEEE   754浮点数格式,取得尾数,仅仅适用于Intel   系列   cpu    
          WORD   *pWord=(WORD   *)(&a)+3;  
           
          *pWord   &=   0x800f;     //清除阶码  
          *pWord   |=   0x3ff0;     //重置阶码  
          return   a;  
  }  
   
  //     必须     1.0   <=x   <2.0  
  double   my_ln(double   x)  
  //   误差小于1e-5  
  {  
  double   e1,e2,e3,e5,e7;  
  x-=1.0;  
  e1=   x/(2+x);  
  e2=e1*e1;  
  e3=e1*e2;  
  e5=e3*e2;  
  e7=e5*e2;  
  return   2*(e1+   (1.0/3)*e3   +(1.0/5)*e5   +   (1.0/7)*e7);  
  }  
   
  double   log2(double   x)  
  {  
  double   f;  
  if   (x<=0)  
  return   0;   //负数不能求对数  
          short   k=   GetExpBase2(x);  
  f=   GetMantissa(x);  
  return   k   +   my_ln(f)   *   LOG2E;  
  }  
   
  int   main(int   argc,   char*   argv[])  
  {  
  double   e0,e1,e2,e3;  
  e0=log2(1.9999999);  
  e1=log2(0.1);  
  e2=log2(0.01);  
  e3=log2(0.0005);  
   
  return   0;  
  }Top

5 楼liangbch(宝宝)回复于 2005-09-06 15:15:11 得分 0

函数   log2   不仅适用于   参数小于1的情况,也适用于任何大于0的浮点数,且可保证精确到4位小数,如果想得到更高的精度,请修改函数   my_ln   ,多计算几项。Top

6 楼mysword(一怒拔剑)回复于 2005-09-06 16:00:58 得分 0

还可以按照手算对数的方法求到任意精度Top

7 楼happy__888([顾问团]寻开心 www.e-jjj.com)回复于 2005-09-06 16:06:56 得分 0

my_ln是利用ln的展开式进行计算的,精度是依靠展开式子的长度来保证的  
  最大误差发生在1.m当中的m接近1的时候,可以再加一段测试误差的代码:  
        在展开到e1的时候,最大误差是:       0.03  
        在展开到e3的时候,最大误差是:       0.0025  
        在展开到e5的时候,最大误差是:       0.00027  
        在展开到e7的时候,最大的误差是;   0.000018  
  展开的级数约高,进度约好,但是对应的计算越多  
         
  按照上述的方法,现在的计算速度已经比直接计算log(x)   *   s   慢了  
  s   =   1.0   /   log(2)   是一个常量。  
   
   
  在计算1.m的时候,用查表的速度更快,牺牲空间换取速度,当然精度越高,表越长Top

8 楼happy__888([顾问团]寻开心 www.e-jjj.com)回复于 2005-09-06 16:10:19 得分 0

在e5的时候,速度比log自身的运算慢3倍  
  即便是e1也是慢2倍的  
  速度慢,就达不到要求了  
  测试的方法,代码仿照   宝宝的前文,建立如下:  
  double   s   =   1.0f   /   log(2);  
  clock_t   start,   finish;  
       
  start   =   clock();  
  for   (   int   i=0;   i<1000000;   i++   )     p   =   log(1.9999)   *   s;  
  finish   =   clock();  
  double   duration1   =   (double)(finish   -   start);  
   
  start   =   clock();  
  for   (   i=0;   i<1000000;   i++   )     p   =   log2(1.9999);  
  finish   =   clock();  
   
  double   duration2   =   (double)(finish   -   start);  
  printf("x=%lf,   error=%lf\n",   duration1,   duration2);  
   
  因此应该是利用浮点数的内存结构,直接提取指数和小数的部分,然后查表为快  
  Top

9 楼happy__888([顾问团]寻开心 www.e-jjj.com)回复于 2005-09-06 16:42:43 得分 0

关于查表是建立一个1到2之间的数据表  
  根据前面的描述1.m后面的m数值可以从浮点数的内存结构当中直接的提取  
  提取出来后按照整数来理解它  
  根据表的长度,选择适当几位提取  
  表的长度也是2^n为好,这样就可以直接使用,避免了一些不必要的转换和计算  
  Top

相关问题

  • 小数点精度的问题?
  • 请问如何设定精度(小数点后面的位数)?
  • Double.ToString如何指定小数点后的精度
  • 数据窗口的computed field计算结果,小数点后一大串,怎样只取小数点后两位?
  • 怎样使计算结果只保留小数点后两位?
  • 怎么让计算结果的小数点后只取2位?
  • 怎样让计算结果只保留两位小数点
  • 浮点值计算出现小数点错误
  • Java计算中,如何设定小数点保留位数?
  • 关于Float数据类型,取小数点后几位精度的问题。

关键词

  • pword
  • 阶码
  • double

得分解答快速导航

  • 帖主:FirstTime
  • happy__888
  • liangbch

相关链接

  • CSDN Blog
  • 技术文档
  • 代码下载
  • 第二书店
  • 读书频道

广告也精彩

反馈

请通过下述方式给我们反馈
反馈
提问
网站简介|广告服务|VIP资费标准|银行汇款帐号|网站地图|帮助|联系方式|诚聘英才|English|问题报告
北京创新乐知广告有限公司 版权所有, 京 ICP 证 070598 号
世纪乐知(北京)网络技术有限公司 提供技术支持
Copyright © 2000-2008, CSDN.NET, All Rights Reserved
GongshangLogo