Java源码解读 – 常量52429

本篇文章最早源于我在知乎的回答,传送门

52429作为常量经常出现在openjava中openjdk8-b132的java.lang.Integer类的456行为例子:

// Fall thru to fast mode for smaller numbers
// assert(i <= 65536, i);
for (;;) {
    q = (i * 52429) >>> (16+3);
    r = i - ((q << 3) + (q << 1));  // r = i-(q*10) ...
    buf [--charPos] = digits [r];
    i = q;
    if (i == 0) break;
}

固定的形式是一个整型变量乘上52429,然后向右移19位。很自然想到2^19=524288,那么这个52429就不难理解了,应该就是除10的操作。除法是很慢的,而乘法和以为却相对较快,所以为了优化这一点点的速度,java采用了乘52429再移19位的方法。对于为什么选择52429,这里列出几个取值的精度:

103/1024≈0.1006 (2^10)
205/2048≈0.100098 (2^11)
……
26215/262144≈0.100002 (2^18)
52429/524288≈0.10000038 (2^19)
104858/1048576≈0.10000038 (2^20)

可见,到2^19次方左右,除10的精度已经非常高了。那么为什么不再选几位呢?原因很简单:首先就是,java中整型占32位,而52429的二进制是1100110011001101(16位),65535的二进制是111111111111111(16位),相乘结果为31位。通过阅读上述源码的这个方法可知,i是不会大于65535的(注释中也提到:assert(i <= 65536, i);),所以算上符号位,能达到精度最大而又不溢出的也就是2^19了。

后记

Sun公司的程序员对java的性能优化是非常仔细且彻底的,这一点在阅读openjdk的时候相信肯定会体会到。对于本文中除法的优化,按照现今计算平台来看,说实在的,几乎是没有效果的。但是java还是做了优化。在阅读openjdk的时候,还会遇到很多类似的东西,这时候就应该多多思考:这些代码有什么用?能不能换成别的?这样,相信对java也会有更深的理解。

分享到

KAAAsS

喜欢二次元的程序员,喜欢发发教程,或者偶尔开坑。(←然而并不打算填)

相关日志

  1. 没有图片
  2. 没有图片
  3. 没有图片
  4. 没有图片
  5. 没有图片

评论

还没有评论。

在此评论中不能使用 HTML 标签。