Java Mutable BigInteger类

时间:2011-10-22 22:25:00

标签: java performance precision biginteger mutable

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

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

3 个答案:

答案 0 :(得分:8)

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

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

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的行为与你期望的完全不同。

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

答案 1 :(得分:2)

JScience 有一个类调用 LargeInteger ,它也是不可变的,但与BigInteger相比,他们声称这些性能显着提升。

http://jscience.org/

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

答案 2 :(得分:0)

我复制了MutableBigInteger,然后注释了一些方法&#39;我不需要的身体,添加一个不错的

throw new UnsupportedOperationException("...");

被调用时。

here就是这样。

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);
    }
}