Java Mutable BigInteger类

我正在使用BigIntegers进行计算,它使用一个调用multiply()大约1000亿次的循环,而BigInteger创建的新对象使得它非常慢。 我希望有人写过或找到了MutableBigInteger类。 我在java.math包中找到了MutableBigInteger,但它是私有的,当我将代码复制到一个新类时,会出现很多错误,其中大部分都是我不知道如何修复的。

像MutableBigInteger这样的Java类有哪些实现允许修改值?

他们有什么特别的理由你不能用reflection来获得课程的访问权限吗?

我能够毫无问题地这样做,这是代码:

 public static void main(String[] args) throws Exception { Constructor constructor = Class.forName("java.math.MutableBigInteger").getDeclaredConstructor(int.class); constructor.setAccessible(true); Object x = constructor.newInstance(new Integer(17)); Object y = constructor.newInstance(new Integer(19)); Constructor constructor2 = Class.forName("java.math.MutableBigInteger").getDeclaredConstructor(x.getClass()); constructor2.setAccessible(true); Object z = constructor.newInstance(new Integer(0)); Object w = constructor.newInstance(new Integer(0)); Method m = x.getClass().getDeclaredMethod("multiply", new Class[] { x.getClass(), x.getClass()}); Method m2 = x.getClass().getDeclaredMethod("mul", new Class[] { int.class, x.getClass()}); m.setAccessible(true); m2.setAccessible(true); // Slightly faster than BigInteger for (int i = 0; i < 200000; i++) { m.invoke(x, y, z); w = z; z = x; x = w; } // Significantly faster than BigInteger and the above loop for (int i = 0; i < 200000; i++) { m2.invoke(x, 19, x); } BigInteger n17 = new BigInteger("17"); BigInteger n19 = new BigInteger("19"); BigInteger bigX = n17; // Slowest for (int i = 0; i < 200000; i++) { bigX = bigX.multiply(n19); } } 

编辑:我决定再玩一下,看起来java.math.MutableBigInteger的行为并不像你期望的那样。

它在乘法运算时的运算方式不同,当它在分配给自身时必须增加内部数组的大小时会抛出一个很好的exception。 我猜的东西是相当可观的。 相反,我必须交换对象,以便始终将结果放入不同的MutableBigInteger。 经过几千次计算后,reflection的开销变得可以忽略不计。 随着操作数量的增加,MutableBigInteger确实最终领先并提供越来越好的性能。 如果使用带有整数原语的'mul'函数作为要乘的值,MutableBigInteger的运行速度几乎比使用BigInteger快10倍。 我想这真的归结为你需要乘以的价值。 无论哪种方式,如果你使用MutableBigInteger的reflection运行这个计算“1000亿次”,它将比BigInteger运行得更快,因为会有“更少”的内存分配,它会缓存reflection操作,从reflection中消除开销。

JScience有一个类调用LargeInteger ,它也是不可变的,但是与BigInteger相比,它们声称它们的性能得到了显着改善。

http://jscience.org/

APFloat的Apint也许值得一试。 http://www.apfloat.org/apfloat_java/

我复制了MutableBigInteger,然后注释了一些我不需要的方法,添加了一个很好的

 throw new UnsupportedOperationException("..."); 

在被调用时。

这是它的样子。

在Revisions中,您可以看到原始java.math.MutableBigInteger的变化。

我还添加了一些方便的方法,

 public void init(long val) {}; public MutableBigInteger(long val) {}; // To save previous value before modifying. public void addAndBackup(MutableBigInteger addend) {} // To restore previous value after modifying. public void restoreBackup() {} 

这是我如何使用它:

 private BigInteger traverseToFactor(BigInteger offset, BigInteger toFactorize, boolean forward) { MutableBigInteger mbiOffset = new MutableBigInteger(offset); MutableBigInteger mbiToFactorize = new MutableBigInteger(toFactorize); MutableBigInteger blockSize = new MutableBigInteger(list.size); if (! MutableBigInteger.ZERO.equals(mbiOffset.remainder(blockSize))) { throw new ArithmeticException("Offset not multiple of blockSize"); } LongBigArrayBigList pattern = (LongBigArrayBigList) list.getPattern(); while (true) { MutableBigInteger divisor = new MutableBigInteger(mbiOffset); for (long i = 0; i < pattern.size64(); i++) { long testOperand = pattern.getLong(i); MutableBigInteger.UNSAFE_AUX_VALUE.init(testOperand); divisor.addAndBackup(MutableBigInteger.UNSAFE_AUX_VALUE); if (MutableBigInteger.ZERO.equals(mbiToFactorize.remainder(divisor))) { return divisor.toBigInteger(); } divisor.restoreBackup(); } if (forward) { mbiOffset.add(blockSize); } else { mbiOffset.subtract(blockSize); } System.out.println(mbiOffset); } }