今天遇到问题需要计算以2为底的对数值(需要整数),找了半天API中log函数有自然对数,以10为底的对数,没有以2为底的,~~o(>_<)o ~~,API中提供的方法返回的都是double类型的,可能你会觉得,不就这么简单嘛,其实这里面学问也挺大的呢,且听我慢慢叙来~~

  • 方法一:
我们都知道
            log[a]x log[b]x = ---------            log[a]b
因此呢,我们可以用一下的方法计算 log2(或者用自然对数)
            log[10]x log[2]x = ----------            log[10]2
即:(int) (Math.log(x) / Math.log(base));
如果只是计算以2为底的对数,上面的方法没有什么问题,如果以3或者其他数为底的时候,上面的方法就暗藏玄机了,强制装换成Int类型不一定可靠,以前写程序遇到过强制转后精度丢失的问题,结果查了半天才把这个bug找出来。上面的计算方法其实也是有问题的,无论什么时候,用浮点数运算去代替整数计算时都要小心。浮点数的运算是不确切的,你也不能很确切的知道(int)(Math.log(65536)/Math.log(2))的值是多少,例如:Math.ceil(Math.log(1<<29) / Math.log(2))计算的结果是30,而它的正确值应该是29,我不能很找到哪些值用(int)(Math.log(x)/Math.log(2))的时候会不正确, (just because there are only 32 "dangerous" values),
注:下面的与本主题无关,只是就这个问题说开去,证明一个问题,当底数不是2时,用上述方法是有问题的~~
下面就用遍历的方法把这些值打印出来:
  1. static int pow(int base,int power){
  2. int result =1;
  3. for(int i =0; i < power; i++)
  4. result *= base;
  5. return result;
  6. }
  7. private static void test(int base,int pow){
  8. int x = pow(base, pow);
  9. if(pow != log(x, base))
  10. System.out.println(String.format("error at %d^%d", base, pow));
  11. if(pow!=0&&(pow-1)!= log(x-1, base))
  12. System.out.println(String.format("error at %d^%d-1", base, pow));
  13. }
  14. static int log(int x,int base)
  15. {
  16. return(int)(Math.log(x)/Math.log(base));
  17. }
  18. public static void main(String[] args){
  19. for(int base =2; base <500; base++){
  20. int maxPow =(int)(Math.log(Integer.MAX_VALUE)/Math.log(base));
  21. for(int pow =0; pow <= maxPow; pow++){
  22. test(base, pow);
  23. }
  24. }
  25. }
结果是:
error at 3^5error at 3^10error at 3^13error at 3^15error at 3^17error at 9^5error at 10^3error at 10^6error at 10^9error at 11^7error at 12^7...

也就是说,当底为第一个数,指数为第二个数时,用(int)(Math.log(x)/Math.log(base))是有问题的,又有人提出用近似值("epsilon")来减小误差:(int)(Math.log(x)/Math.log(2)+1e-10),这种方法也是可以的;

  • 方法二:
  1. public static int log2(int n){
  2. if(n <=0)throw new IllegalArgumentException();
  3. return31-Integer.numberOfLeadingZeros(n);
  4. }

UPDMy integer arithmetic function is 10 times faster than Math.log(n)/Math.log(2).

上面的方法会不会有性能问题呢,可能你会不以为然,有人给出了更简便的方法,我们知道移位操作比遍历和运算要快得多;
  • 方法三:
  1. public static int log2X(int bits )// returns 0 for bits=0
  2. {
  3. int log =0;
  4. if(( bits &0xffff0000)!=0){ bits >>>=16; log =16;}
  5. if( bits >=256){ bits >>>=8; log +=8;}
  6. if( bits >=16 ){ bits >>>=4; log +=4;}
  7. if( bits >=4 ){ bits >>>=2; log +=2;}
  8. return log +( bits >>>1);
  9. }
  10. //自己慢慢理解吧^_^

这种方法要比 Integer.numberOfLeadingZeros() 快上20-30%,要比一个如下所示的基于Math.log()
的 方法几乎快10 倍:

  1. private static final double log2div =Math.log(2);
  2. public static int log2fp(int bits )
  3. {
  4. if( bits ==0)
  5. return0;// or throw exception
  6. return(int)(Math.log( bits &0xffffffffL)/ log2div );
  7. }

我说的没错吧,可能你觉得太钻牛角尖了,也是,不过别人能用更优雅,效率更高的方法实现相 同的功能,也
值得借鉴一下,并且以后在用浮点数代替整数计算时也要晓得,会不会有“陷阱”~~

转载于:https://blog.51cto.com/lbrant/469310

How do you calculate log base 2 in Java for integers?相关推荐

  1. eclipse报错:An error has occurred. See error log for more details. java.lang.NullPointerException

    eclipse一直不停的报错: An error has occurred. See error log for more details. java.lang.NullPointerExceptio ...

  2. 解决Sentinel log base directory is: C:\Users***\logs\csp\

    在项目总是会生成csp文件,而且会越来越多,自己的项目里面也没有用到Sentinel ,但依赖里面有引用,删掉依赖就好了.

  3. calculate整数计算(Base父类及子类Sub)

    >calculate整数计算(Base父类及子类Sub)< 定义一个父类 Base 中的方法 calculate() ,该方法用于计算两个数的乘积(X*Y).定义一个 Base 类的子类 ...

  4. Android 解读Event和Main Log

    1 Android P EventLogTags文件 Android P 9.0.0 所有EventLogTags文件List: system/bt/EventLogTags.logtags syst ...

  5. java如何算log_用java代码计算Log(a)b

    1 java标准包提供了自然对数的计算方法,2 其他的对数计算可以转换为自然对数的计算. Sun的J2SE提供了一个计算自然对数方法--double java.lang.Math.log(double ...

  6. Android_8.1 Log 系统源码分析

    文章目录 0x01 [Android Log框架推荐](https://www.jianshu.com/p/64b63e51fd4c) 1. [logger](https://github.com/o ...

  7. NXP S32K146 打印LOG函数分析

    最近从STM32换成NXP的S32K1平台做项目,从读手册调外设驱动开始,关于外设驱动是怎么调的,我用的软件是S32 Design Studio for ARM Version 2.2 在官网下载的, ...

  8. Log4j配置输出log文件的相对路径

    转载请注明来源-作者@loongshawn:http://blog.csdn.net/loongshawn/article/details/52967694 1 配置log4j log4j.prope ...

  9. Android event log 说明

    目录 1. Android 系统中对于 event log 的定义文件 2. event 的类别 3. 手机中查看 event log 事件信息 1. Android 系统中对于 event log ...

  10. Android 解读main log和event log日志信息

    ENV:Android M 6.0.1 一 分析main log 1.1 通过adb logcat输出的main log文件,每一行都是以如下格式作为开头信息 格式:timestamp PID TID ...

最新文章

  1. cpu安装_CPU是AMD的,老台式电脑可以加装固态硬盘安装Win10系统吗?
  2. WPF - 资源收集
  3. Spring基于注解的AOP配置
  4. [转载] 羽毛球——学打羽毛球 09 步法的基本概念
  5. [编程题]数字分类 (20)
  6. api接口返回动态的json格式?我太难了,尝试一下 linq to json
  7. Python 开发者 2017 应该关注的 7 个类库
  8. php最难,那个PHP中号称最难的‘递归函数’
  9. jave使用corenlp
  10. 【实用工具系列】MathCAD入门安装及快速上手使用教程
  11. 香港服务器的数据泄露是什么?怎样预防?
  12. java爬虫实战(3):网易云音乐评论,歌曲,歌单,歌词下载
  13. huihoo和中国的开源,路在何方???
  14. DIV+CSS布局基本流程及实例介绍
  15. 基于Qt的音乐播放器(二)切换歌曲,调节音量,调节语速,暂停
  16. 请编写一个程序,使用字典存储学生信息,学生信息包括学号和姓名,请根据学生学号从小到大的顺序输出学生信息。
  17. 计算机应用最普遍的汉字字符编码是什么,计算机中目前最普遍使用的汉字字符编码是什么...
  18. 基于pyqt5开发的图书管理系统UI(带登录页面)
  19. 财路网每日原创推送:浅谈:区块连数字身份
  20. 修改falcon的钉钉告警格式

热门文章

  1. java程序拦截dde漏洞问题_Office DDE漏洞学习笔记
  2. LINUX编译mate-desktop/pluma-1.24.0文本编辑器
  3. /bin/sh: 1: tclsh: not found
  4. JAVA压缩、解压,使用Apache Common Compress包下载链接
  5. 南半球左撇子的人是否多一些
  6. python turtle代码示例-Python turtle.left方法代码示例
  7. 免费文件分发服务器,文件分发服务器 AWS CloudFront(CDN)使用入门-以S3为例 Lebal:Research...
  8. nginx代理php不能跳转页面,nginx 解决首页跳转问题详解
  9. win2012 定时自动备份mysql_SQL SERVER 2012数据库自动备份的方法
  10. ai画面怎么调大小_AI人脸抓拍摄像机安装指导,这样安装抓拍更准