java biginteger log_java – BigInteger:计算可伸缩方法中的小数位数

这看起来很有效.我还没有进行详尽的测试,或者我没有运行任何时间测试,但它似乎有一个合理的运行时间.

public class Test {

/**

* Optimised for huge numbers.

*

* http://en.wikipedia.org/wiki/Logarithm#Change_of_base

*

* States that log[b](x) = log[k](x)/log[k](b)

*

* We can get log[2](x) as the bitCount of the number so what we need is

* essentially bitCount/log[2](10). Sadly that will lead to inaccuracies so

* here I will attempt an iterative process that should achieve accuracy.

*

* log[2](10) = 3.32192809488736234787 so if I divide by 10^(bitCount/4) we

* should not go too far. In fact repeating that process while adding (bitCount/4)

* to the running count of the digits will end up with an accurate figure

* given some twiddling at the end.

*

* So here's the scheme:

*

* While there are more than 4 bits in the number

* Divide by 10^(bits/4)

* Increase digit count by (bits/4)

*

* Fiddle around to accommodate the remaining digit - if there is one.

*

* Essentially - each time around the loop we remove a number of decimal

* digits (by dividing by 10^n) keeping a count of how many we've removed.

*

* The number of digits we remove is estimated from the number of bits in the

* number (i.e. log[2](x) / 4). The perfect figure for the reduction would be

* log[2](x) / 3.3219... so dividing by 4 is a good under-estimate. We

* don't go too far but it does mean we have to repeat it just a few times.

*/

private int log10(BigInteger huge) {

int digits = 0;

int bits = huge.bitLength();

// Serious reductions.

while (bits > 4) {

// 4 > log[2](10) so we should not reduce it too far.

int reduce = bits / 4;

// Divide by 10^reduce

huge = huge.divide(BigInteger.TEN.pow(reduce));

// Removed that many decimal digits.

digits += reduce;

// Recalculate bitLength

bits = huge.bitLength();

}

// Now 4 bits or less - add 1 if necessary.

if ( huge.intValue() > 9 ) {

digits += 1;

}

return digits;

}

// Random tests.

Random rnd = new Random();

// Limit the bit length.

int maxBits = BigInteger.TEN.pow(200000).bitLength();

public void test() {

// 100 tests.

for (int i = 1; i <= 100; i++) {

BigInteger huge = new BigInteger((int)(Math.random() * maxBits), rnd);

// Note start time.

long start = System.currentTimeMillis();

// Do my method.

int myLength = log10(huge);

// Record my result.

System.out.println("Digits: " + myLength+ " Took: " + (System.currentTimeMillis() - start));

// Check the result.

int trueLength = huge.toString().length() - 1;

if (trueLength != myLength) {

System.out.println("WRONG!! " + (myLength - trueLength));

}

}

}

public static void main(String args[]) {

new Test().test();

}

}

在我的Celeron M笔记本电脑上花了大约3秒钟,所以它应该在一些不错的套件上达到2秒.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值