Java 可变 BigInteger 类

发布于 2024-12-11 16:16:24 字数 260 浏览 0 评论 0原文

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

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

I am doing calculations with BigIntegers that uses a loop that calls multiply() about 100 billion times, and the new object creation from the BigInteger is making it very slow. I was hoping somebody had written or found a MutableBigInteger class. I found the MutableBigInteger in the java.math package, but it is private and when I copy the code into a new class, many errors come up, most of which I don't know how to fix.

What implementations exist of a Java class like MutableBigInteger that allows modifying the value in place?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

梦晓ヶ微光ヅ倾城 2024-12-18 16:16:24

他们是否有任何特殊原因导致您无法使用反射来访问该类?

我能够毫无问题地做到这一点,这是代码:

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 运行得更快,因为内存分配会“更少”,并且它将缓存反射操作,从而消除反射带来的开销。

Is their any particular reason you cannot use reflection to gain access to the class?

I was able to do so without any problems, here is the code:

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

Edit:
I decided to play around with a bit more, it does appear that java.math.MutableBigInteger doesn't behave exactly as you would expect.

It operates differently when you multiply and it will throw a nice exception when it has to increase the size of the internal array when assigning to itself. Something I guess is fairly expected. Instead I have to swap around the objects so that it is always placing the result into a different MutableBigInteger. After a couple thousand calculations the overhead from reflection becomes negligible. MutableBigInteger does end up pulling ahead and offers increasingly better performance as the number of operations increases. If you use the 'mul' function with an integer primitive as the value to multiply with, the MutableBigInteger runs almost 10 times faster than using BigInteger. I guess it really boils down to what value you need to multiply with. Either way if you ran this calculation "100 billion times" using reflection with MutableBigInteger, it would run faster than BigInteger because there would be "less" memory allocation and it would cache the reflective operations, removing overhead from reflection.

脸赞 2024-12-18 16:16:24

JScience 有一个名为 LargeInteger 的类,它也是不可变的,但他们声称与 BigInteger 相比,性能显着提高。

http://jscience.org/

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

JScience has a class call LargeInteger, which is also immutable, but which they claim has significantly improved perfomance compared to BigInteger.

http://jscience.org/

APFloat's Apint might be worth checking out too. http://www.apfloat.org/apfloat_java/

尛丟丟 2024-12-18 16:16:24

我复制了 MutableBigInteger,然后注释掉了一些我不需要的方法体,并

throw new UnsupportedOperationException("...");

在调用时添加了一个 Nice 。

这里是它的外观。

修订中,您可以看到与原始 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);
    }
}

I copied MutableBigInteger, then commented out some methods' bodies I dind't need, adding a nice

throw new UnsupportedOperationException("...");

when invoked.

here is how it looks.

In Revisions you can see what's changed from the original java.math.MutableBigInteger.

I also added some convenience methods,

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() {}

Here is how I used it:

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);
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文