All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jdk.internal.math.FDBigInteger Maven / Gradle / Ivy

There is a newer version: 17.alpha.0.57
Show newest version
/*
 * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
package jdk.internal.math;

import jdk.internal.misc.CDS;

import java.math.BigInteger;
import java.util.Arrays;
//@ model import org.jmlspecs.models.JMLMath;

/**
 * A simple big integer package specifically for floating point base conversion.
 */
public /*@ spec_bigint_math @*/ class FDBigInteger {

    //
    // This class contains many comments that start with "/*@" mark.
    // They are behavourial specification in
    // the Java Modelling Language (JML):
    // http://www.eecs.ucf.edu/~leavens/JML//index.shtml
    //

    /*@
    @ public pure model static \bigint UNSIGNED(int v) {
    @     return v >= 0 ? v : v + (((\bigint)1) << 32);
    @ }
    @
    @ public pure model static \bigint UNSIGNED(long v) {
    @     return v >= 0 ? v : v + (((\bigint)1) << 64);
    @ }
    @
    @ public pure model static \bigint AP(int[] data, int len) {
    @     return (\sum int i; 0 <= 0 && i < len; UNSIGNED(data[i]) << (i*32));
    @ }
    @
    @ public pure model static \bigint pow52(int p5, int p2) {
    @     ghost \bigint v = 1;
    @     for (int i = 0; i < p5; i++) v *= 5;
    @     return v << p2;
    @ }
    @
    @ public pure model static \bigint pow10(int p10) {
    @     return pow52(p10, p10);
    @ }
    @*/

    static final int[] SMALL_5_POW;

    static final long[] LONG_5_POW;

    // Maximum size of cache of powers of 5 as FDBigIntegers.
    private static final int MAX_FIVE_POW = 340;

    // Cache of big powers of 5 as FDBigIntegers.
    private static final FDBigInteger POW_5_CACHE[];

    // Zero as an FDBigInteger.
    public static final FDBigInteger ZERO;

    // Archive proxy
    private static Object[] archivedCaches;

    // Initialize FDBigInteger cache of powers of 5.
    static {
        CDS.initializeFromArchive(FDBigInteger.class);
        Object[] caches = archivedCaches;
        if (caches == null) {
            long[] long5pow = {
                    1L,
                    5L,
                    5L * 5,
                    5L * 5 * 5,
                    5L * 5 * 5 * 5,
                    5L * 5 * 5 * 5 * 5,
                    5L * 5 * 5 * 5 * 5 * 5,
                    5L * 5 * 5 * 5 * 5 * 5 * 5,
                    5L * 5 * 5 * 5 * 5 * 5 * 5 * 5,
                    5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
                    5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
                    5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
                    5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
                    5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
                    5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
                    5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
                    5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
                    5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
                    5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
                    5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
                    5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
                    5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
                    5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
                    5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
                    5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
                    5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
                    5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
                };
            int[] small5pow = {
                    1,
                    5,
                    5 * 5,
                    5 * 5 * 5,
                    5 * 5 * 5 * 5,
                    5 * 5 * 5 * 5 * 5,
                    5 * 5 * 5 * 5 * 5 * 5,
                    5 * 5 * 5 * 5 * 5 * 5 * 5,
                    5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
                    5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
                    5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
                    5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
                    5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
                    5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5
                };
            FDBigInteger[] pow5cache = new FDBigInteger[MAX_FIVE_POW];
            int i = 0;
            while (i < small5pow.length) {
                FDBigInteger pow5 = new FDBigInteger(new int[] { small5pow[i] }, 0);
                pow5.makeImmutable();
                pow5cache[i] = pow5;
                i++;
            }
            FDBigInteger prev = pow5cache[i - 1];
            while (i < MAX_FIVE_POW) {
                pow5cache[i] = prev = prev.mult(5);
                prev.makeImmutable();
                i++;
            }
            FDBigInteger zero = new FDBigInteger(new int[0], 0);
            zero.makeImmutable();
            archivedCaches = caches = new Object[] {small5pow, long5pow, pow5cache, zero};
        }
        SMALL_5_POW = (int[])caches[0];
        LONG_5_POW = (long[])caches[1];
        POW_5_CACHE = (FDBigInteger[])caches[2];
        ZERO = (FDBigInteger)caches[3];
    }

    // Constant for casting an int to a long via bitwise AND.
    private static final long LONG_MASK = 0xffffffffL;

    //@ spec_public non_null;
    private int data[];  // value: data[0] is least significant
    //@ spec_public;
    private int offset;  // number of least significant zero padding ints
    //@ spec_public;
    private int nWords;  // data[nWords-1]!=0, all values above are zero
                 // if nWords==0 -> this FDBigInteger is zero
    //@ spec_public;
    private boolean isImmutable = false;

    /*@
     @ public invariant 0 <= nWords && nWords <= data.length && offset >= 0;
     @ public invariant nWords == 0 ==> offset == 0;
     @ public invariant nWords > 0 ==> data[nWords - 1] != 0;
     @ public invariant (\forall int i; nWords <= i && i < data.length; data[i] == 0);
     @ public pure model \bigint value() {
     @     return AP(data, nWords) << (offset*32);
     @ }
     @*/

    /**
     * Constructs an FDBigInteger from data and padding. The
     * data parameter has the least significant int at
     * the zeroth index. The offset parameter gives the number of
     * zero ints to be inferred below the least significant element
     * of data.
     *
     * @param data An array containing all non-zero ints of the value.
     * @param offset An offset indicating the number of zero ints to pad
     * below the least significant element of data.
     */
    /*@
     @ requires data != null && offset >= 0;
     @ ensures this.value() == \old(AP(data, data.length) << (offset*32));
     @ ensures this.data == \old(data);
     @*/
    private FDBigInteger(int[] data, int offset) {
        this.data = data;
        this.offset = offset;
        this.nWords = data.length;
        trimLeadingZeros();
    }

    /**
     * Constructs an FDBigInteger from a starting value and some
     * decimal digits.
     *
     * @param lValue The starting value.
     * @param digits The decimal digits.
     * @param kDigits The initial index into digits.
     * @param nDigits The final index into digits.
     */
    /*@
     @ requires digits != null;
     @ requires 0 <= kDigits && kDigits <= nDigits && nDigits <= digits.length;
     @ requires (\forall int i; 0 <= i && i < nDigits; '0' <= digits[i] && digits[i] <= '9');
     @ ensures this.value() == \old(lValue * pow10(nDigits - kDigits) + (\sum int i; kDigits <= i && i < nDigits; (digits[i] - '0') * pow10(nDigits - i - 1)));
     @*/
    public FDBigInteger(long lValue, char[] digits, int kDigits, int nDigits) {
        int n = Math.max((nDigits + 8) / 9, 2);        // estimate size needed.
        data = new int[n];      // allocate enough space
        data[0] = (int) lValue;    // starting value
        data[1] = (int) (lValue >>> 32);
        offset = 0;
        nWords = 2;
        int i = kDigits;
        int limit = nDigits - 5;       // slurp digits 5 at a time.
        int v;
        while (i < limit) {
            int ilim = i + 5;
            v = (int) digits[i++] - (int) '0';
            while (i < ilim) {
                v = 10 * v + (int) digits[i++] - (int) '0';
            }
            multAddMe(100000, v); // ... where 100000 is 10^5.
        }
        int factor = 1;
        v = 0;
        while (i < nDigits) {
            v = 10 * v + (int) digits[i++] - (int) '0';
            factor *= 10;
        }
        if (factor != 1) {
            multAddMe(factor, v);
        }
        trimLeadingZeros();
    }

    /**
     * Returns an FDBigInteger with the numerical value
     * 5p5 * 2p2.
     *
     * @param p5 The exponent of the power-of-five factor.
     * @param p2 The exponent of the power-of-two factor.
     * @return 5p5 * 2p2
     */
    /*@
     @ requires p5 >= 0 && p2 >= 0;
     @ assignable \nothing;
     @ ensures \result.value() == \old(pow52(p5, p2));
     @*/
    public static FDBigInteger valueOfPow52(int p5, int p2) {
        if (p5 != 0) {
            if (p2 == 0) {
                return big5pow(p5);
            } else if (p5 < SMALL_5_POW.length) {
                int pow5 = SMALL_5_POW[p5];
                int wordcount = p2 >> 5;
                int bitcount = p2 & 0x1f;
                if (bitcount == 0) {
                    return new FDBigInteger(new int[]{pow5}, wordcount);
                } else {
                    return new FDBigInteger(new int[]{
                            pow5 << bitcount,
                            pow5 >>> (32 - bitcount)
                    }, wordcount);
                }
            } else {
                return big5pow(p5).leftShift(p2);
            }
        } else {
            return valueOfPow2(p2);
        }
    }

    /**
     * Returns an FDBigInteger with the numerical value
     * value * 5p5 * 2p2.
     *
     * @param value The constant factor.
     * @param p5 The exponent of the power-of-five factor.
     * @param p2 The exponent of the power-of-two factor.
     * @return value * 5p5 * 2p2
     */
    /*@
     @ requires p5 >= 0 && p2 >= 0;
     @ assignable \nothing;
     @ ensures \result.value() == \old(UNSIGNED(value) * pow52(p5, p2));
     @*/
    public static FDBigInteger valueOfMulPow52(long value, int p5, int p2) {
        assert p5 >= 0 : p5;
        assert p2 >= 0 : p2;
        int v0 = (int) value;
        int v1 = (int) (value >>> 32);
        int wordcount = p2 >> 5;
        int bitcount = p2 & 0x1f;
        if (p5 != 0) {
            if (p5 < SMALL_5_POW.length) {
                long pow5 = SMALL_5_POW[p5] & LONG_MASK;
                long carry = (v0 & LONG_MASK) * pow5;
                v0 = (int) carry;
                carry >>>= 32;
                carry = (v1 & LONG_MASK) * pow5 + carry;
                v1 = (int) carry;
                int v2 = (int) (carry >>> 32);
                if (bitcount == 0) {
                    return new FDBigInteger(new int[]{v0, v1, v2}, wordcount);
                } else {
                    return new FDBigInteger(new int[]{
                            v0 << bitcount,
                            (v1 << bitcount) | (v0 >>> (32 - bitcount)),
                            (v2 << bitcount) | (v1 >>> (32 - bitcount)),
                            v2 >>> (32 - bitcount)
                    }, wordcount);
                }
            } else {
                FDBigInteger pow5 = big5pow(p5);
                int[] r;
                if (v1 == 0) {
                    r = new int[pow5.nWords + 1 + ((p2 != 0) ? 1 : 0)];
                    mult(pow5.data, pow5.nWords, v0, r);
                } else {
                    r = new int[pow5.nWords + 2 + ((p2 != 0) ? 1 : 0)];
                    mult(pow5.data, pow5.nWords, v0, v1, r);
                }
                return (new FDBigInteger(r, pow5.offset)).leftShift(p2);
            }
        } else if (p2 != 0) {
            if (bitcount == 0) {
                return new FDBigInteger(new int[]{v0, v1}, wordcount);
            } else {
                return new FDBigInteger(new int[]{
                         v0 << bitcount,
                        (v1 << bitcount) | (v0 >>> (32 - bitcount)),
                        v1 >>> (32 - bitcount)
                }, wordcount);
            }
        }
        return new FDBigInteger(new int[]{v0, v1}, 0);
    }

    /**
     * Returns an FDBigInteger with the numerical value
     * 2p2.
     *
     * @param p2 The exponent of 2.
     * @return 2p2
     */
    /*@
     @ requires p2 >= 0;
     @ assignable \nothing;
     @ ensures \result.value() == pow52(0, p2);
     @*/
    private static FDBigInteger valueOfPow2(int p2) {
        int wordcount = p2 >> 5;
        int bitcount = p2 & 0x1f;
        return new FDBigInteger(new int[]{1 << bitcount}, wordcount);
    }

    /**
     * Removes all leading zeros from this FDBigInteger adjusting
     * the offset and number of non-zero leading words accordingly.
     */
    /*@
     @ requires data != null;
     @ requires 0 <= nWords && nWords <= data.length && offset >= 0;
     @ requires nWords == 0 ==> offset == 0;
     @ ensures nWords == 0 ==> offset == 0;
     @ ensures nWords > 0 ==> data[nWords - 1] != 0;
     @*/
    private /*@ helper @*/ void trimLeadingZeros() {
        int i = nWords;
        if (i > 0 && (data[--i] == 0)) {
            //for (; i > 0 && data[i - 1] == 0; i--) ;
            while(i > 0 && data[i - 1] == 0) {
                i--;
            }
            this.nWords = i;
            if (i == 0) { // all words are zero
                this.offset = 0;
            }
        }
    }

    /**
     * Retrieves the normalization bias of the FDBigIntger. The
     * normalization bias is a left shift such that after it the highest word
     * of the value will have the 4 highest bits equal to zero:
     * {@code (highestWord & 0xf0000000) == 0}, but the next bit should be 1
     * {@code (highestWord & 0x08000000) != 0}.
     *
     * @return The normalization bias.
     */
    /*@
     @ requires this.value() > 0;
     @*/
    public /*@ pure @*/ int getNormalizationBias() {
        if (nWords == 0) {
            throw new IllegalArgumentException("Zero value cannot be normalized");
        }
        int zeros = Integer.numberOfLeadingZeros(data[nWords - 1]);
        return (zeros < 4) ? 28 + zeros : zeros - 4;
    }

    // TODO: Why is anticount param needed if it is always 32 - bitcount?
    /**
     * Left shifts the contents of one int array into another.
     *
     * @param src The source array.
     * @param idx The initial index of the source array.
     * @param result The destination array.
     * @param bitcount The left shift.
     * @param anticount The left anti-shift, e.g., 32-bitcount.
     * @param prev The prior source value.
     */
    /*@
     @ requires 0 < bitcount && bitcount < 32 && anticount == 32 - bitcount;
     @ requires src.length >= idx && result.length > idx;
     @ assignable result[*];
     @ ensures AP(result, \old(idx + 1)) == \old((AP(src, idx) + UNSIGNED(prev) << (idx*32)) << bitcount);
     @*/
    private static void leftShift(int[] src, int idx, int result[], int bitcount, int anticount, int prev){
        for (; idx > 0; idx--) {
            int v = (prev << bitcount);
            prev = src[idx - 1];
            v |= (prev >>> anticount);
            result[idx] = v;
        }
        int v = prev << bitcount;
        result[0] = v;
    }

    /**
     * Shifts this FDBigInteger to the left. The shift is performed
     * in-place unless the FDBigInteger is immutable in which case
     * a new instance of FDBigInteger is returned.
     *
     * @param shift The number of bits to shift left.
     * @return The shifted FDBigInteger.
     */
    /*@
     @ requires this.value() == 0 || shift == 0;
     @ assignable \nothing;
     @ ensures \result == this;
     @
     @  also
     @
     @ requires this.value() > 0 && shift > 0 && this.isImmutable;
     @ assignable \nothing;
     @ ensures \result.value() == \old(this.value() << shift);
     @
     @  also
     @
     @ requires this.value() > 0 && shift > 0 && this.isImmutable;
     @ assignable \nothing;
     @ ensures \result == this;
     @ ensures \result.value() == \old(this.value() << shift);
     @*/
    public FDBigInteger leftShift(int shift) {
        if (shift == 0 || nWords == 0) {
            return this;
        }
        int wordcount = shift >> 5;
        int bitcount = shift & 0x1f;
        if (this.isImmutable) {
            if (bitcount == 0) {
                return new FDBigInteger(Arrays.copyOf(data, nWords), offset + wordcount);
            } else {
                int anticount = 32 - bitcount;
                int idx = nWords - 1;
                int prev = data[idx];
                int hi = prev >>> anticount;
                int[] result;
                if (hi != 0) {
                    result = new int[nWords + 1];
                    result[nWords] = hi;
                } else {
                    result = new int[nWords];
                }
                leftShift(data,idx,result,bitcount,anticount,prev);
                return new FDBigInteger(result, offset + wordcount);
            }
        } else {
            if (bitcount != 0) {
                int anticount = 32 - bitcount;
                if ((data[0] << bitcount) == 0) {
                    int idx = 0;
                    int prev = data[idx];
                    for (; idx < nWords - 1; idx++) {
                        int v = (prev >>> anticount);
                        prev = data[idx + 1];
                        v |= (prev << bitcount);
                        data[idx] = v;
                    }
                    int v = prev >>> anticount;
                    data[idx] = v;
                    if(v==0) {
                        nWords--;
                    }
                    offset++;
                } else {
                    int idx = nWords - 1;
                    int prev = data[idx];
                    int hi = prev >>> anticount;
                    int[] result = data;
                    int[] src = data;
                    if (hi != 0) {
                        if(nWords == data.length) {
                            data = result = new int[nWords + 1];
                        }
                        result[nWords++] = hi;
                    }
                    leftShift(src,idx,result,bitcount,anticount,prev);
                }
            }
            offset += wordcount;
            return this;
        }
    }

    /**
     * Returns the number of ints this FDBigInteger represents.
     *
     * @return Number of ints required to represent this FDBigInteger.
     */
    /*@
     @ requires this.value() == 0;
     @ ensures \result == 0;
     @
     @  also
     @
     @ requires this.value() > 0;
     @ ensures ((\bigint)1) << (\result - 1) <= this.value() && this.value() <= ((\bigint)1) << \result;
     @*/
    private /*@ pure @*/ int size() {
        return nWords + offset;
    }


    /**
     * Computes
     * 
     * q = (int)( this / S )
     * this = 10 * ( this mod S )
     * Return q.
     * 
* This is the iteration step of digit development for output. * We assume that S has been normalized, as above, and that * "this" has been left-shifted accordingly. * Also assumed, of course, is that the result, q, can be expressed * as an integer, {@code 0 <= q < 10}. * * @param S The divisor of this FDBigInteger. * @return q = (int)(this / S). */ /*@ @ requires !this.isImmutable; @ requires this.size() <= S.size(); @ requires this.data.length + this.offset >= S.size(); @ requires S.value() >= ((\bigint)1) << (S.size()*32 - 4); @ assignable this.nWords, this.offset, this.data, this.data[*]; @ ensures \result == \old(this.value() / S.value()); @ ensures this.value() == \old(10 * (this.value() % S.value())); @*/ public int quoRemIteration(FDBigInteger S) throws IllegalArgumentException { assert !this.isImmutable : "cannot modify immutable value"; // ensure that this and S have the same number of // digits. If S is properly normalized and q < 10 then // this must be so. int thSize = this.size(); int sSize = S.size(); if (thSize < sSize) { // this value is significantly less than S, result of division is zero. // just mult this by 10. int p = multAndCarryBy10(this.data, this.nWords, this.data); if(p!=0) { this.data[nWords++] = p; } else { trimLeadingZeros(); } return 0; } else if (thSize > sSize) { throw new IllegalArgumentException("disparate values"); } // estimate q the obvious way. We will usually be // right. If not, then we're only off by a little and // will re-add. long q = (this.data[this.nWords - 1] & LONG_MASK) / (S.data[S.nWords - 1] & LONG_MASK); long diff = multDiffMe(q, S); if (diff != 0L) { //@ assert q != 0; //@ assert this.offset == \old(Math.min(this.offset, S.offset)); //@ assert this.offset <= S.offset; // q is too big. // add S back in until this turns +. This should // not be very many times! long sum = 0L; int tStart = S.offset - this.offset; //@ assert tStart >= 0; int[] sd = S.data; int[] td = this.data; while (sum == 0L) { for (int sIndex = 0, tIndex = tStart; tIndex < this.nWords; sIndex++, tIndex++) { sum += (td[tIndex] & LONG_MASK) + (sd[sIndex] & LONG_MASK); td[tIndex] = (int) sum; sum >>>= 32; // Signed or unsigned, answer is 0 or 1 } // // Originally the following line read // "if ( sum !=0 && sum != -1 )" // but that would be wrong, because of the // treatment of the two values as entirely unsigned, // it would be impossible for a carry-out to be interpreted // as -1 -- it would have to be a single-bit carry-out, or +1. // assert sum == 0 || sum == 1 : sum; // carry out of division correction q -= 1; } } // finally, we can multiply this by 10. // it cannot overflow, right, as the high-order word has // at least 4 high-order zeros! int p = multAndCarryBy10(this.data, this.nWords, this.data); assert p == 0 : p; // Carry out of *10 trimLeadingZeros(); return (int) q; } /** * Multiplies this FDBigInteger by 10. The operation will be * performed in place unless the FDBigInteger is immutable in * which case a new FDBigInteger will be returned. * * @return The FDBigInteger multiplied by 10. */ /*@ @ requires this.value() == 0; @ assignable \nothing; @ ensures \result == this; @ @ also @ @ requires this.value() > 0 && this.isImmutable; @ assignable \nothing; @ ensures \result.value() == \old(this.value() * 10); @ @ also @ @ requires this.value() > 0 && !this.isImmutable; @ assignable this.nWords, this.data, this.data[*]; @ ensures \result == this; @ ensures \result.value() == \old(this.value() * 10); @*/ public FDBigInteger multBy10() { if (nWords == 0) { return this; } if (isImmutable) { int[] res = new int[nWords + 1]; res[nWords] = multAndCarryBy10(data, nWords, res); return new FDBigInteger(res, offset); } else { int p = multAndCarryBy10(this.data, this.nWords, this.data); if (p != 0) { if (nWords == data.length) { if (data[0] == 0) { System.arraycopy(data, 1, data, 0, --nWords); offset++; } else { data = Arrays.copyOf(data, data.length + 1); } } data[nWords++] = p; } else { trimLeadingZeros(); } return this; } } /** * Multiplies this FDBigInteger by * 5p5 * 2p2. The operation will be * performed in place if possible, otherwise a new FDBigInteger * will be returned. * * @param p5 The exponent of the power-of-five factor. * @param p2 The exponent of the power-of-two factor. * @return The multiplication result. */ /*@ @ requires this.value() == 0 || p5 == 0 && p2 == 0; @ assignable \nothing; @ ensures \result == this; @ @ also @ @ requires this.value() > 0 && (p5 > 0 && p2 >= 0 || p5 == 0 && p2 > 0 && this.isImmutable); @ assignable \nothing; @ ensures \result.value() == \old(this.value() * pow52(p5, p2)); @ @ also @ @ requires this.value() > 0 && p5 == 0 && p2 > 0 && !this.isImmutable; @ assignable this.nWords, this.data, this.data[*]; @ ensures \result == this; @ ensures \result.value() == \old(this.value() * pow52(p5, p2)); @*/ public FDBigInteger multByPow52(int p5, int p2) { if (this.nWords == 0) { return this; } FDBigInteger res = this; if (p5 != 0) { int[] r; int extraSize = (p2 != 0) ? 1 : 0; if (p5 < SMALL_5_POW.length) { r = new int[this.nWords + 1 + extraSize]; mult(this.data, this.nWords, SMALL_5_POW[p5], r); res = new FDBigInteger(r, this.offset); } else { FDBigInteger pow5 = big5pow(p5); r = new int[this.nWords + pow5.size() + extraSize]; mult(this.data, this.nWords, pow5.data, pow5.nWords, r); res = new FDBigInteger(r, this.offset + pow5.offset); } } return res.leftShift(p2); } /** * Multiplies two big integers represented as int arrays. * * @param s1 The first array factor. * @param s1Len The number of elements of s1 to use. * @param s2 The second array factor. * @param s2Len The number of elements of s2 to use. * @param dst The product array. */ /*@ @ requires s1 != dst && s2 != dst; @ requires s1.length >= s1Len && s2.length >= s2Len && dst.length >= s1Len + s2Len; @ assignable dst[0 .. s1Len + s2Len - 1]; @ ensures AP(dst, s1Len + s2Len) == \old(AP(s1, s1Len) * AP(s2, s2Len)); @*/ private static void mult(int[] s1, int s1Len, int[] s2, int s2Len, int[] dst) { for (int i = 0; i < s1Len; i++) { long v = s1[i] & LONG_MASK; long p = 0L; for (int j = 0; j < s2Len; j++) { p += (dst[i + j] & LONG_MASK) + v * (s2[j] & LONG_MASK); dst[i + j] = (int) p; p >>>= 32; } dst[i + s2Len] = (int) p; } } /** * Subtracts the supplied FDBigInteger subtrahend from this * FDBigInteger. Assert that the result is positive. * If the subtrahend is immutable, store the result in this(minuend). * If this(minuend) is immutable a new FDBigInteger is created. * * @param subtrahend The FDBigInteger to be subtracted. * @return This FDBigInteger less the subtrahend. */ /*@ @ requires this.isImmutable; @ requires this.value() >= subtrahend.value(); @ assignable \nothing; @ ensures \result.value() == \old(this.value() - subtrahend.value()); @ @ also @ @ requires !subtrahend.isImmutable; @ requires this.value() >= subtrahend.value(); @ assignable this.nWords, this.offset, this.data, this.data[*]; @ ensures \result == this; @ ensures \result.value() == \old(this.value() - subtrahend.value()); @*/ public FDBigInteger leftInplaceSub(FDBigInteger subtrahend) { assert this.size() >= subtrahend.size() : "result should be positive"; FDBigInteger minuend; if (this.isImmutable) { minuend = new FDBigInteger(this.data.clone(), this.offset); } else { minuend = this; } int offsetDiff = subtrahend.offset - minuend.offset; int[] sData = subtrahend.data; int[] mData = minuend.data; int subLen = subtrahend.nWords; int minLen = minuend.nWords; if (offsetDiff < 0) { // need to expand minuend int rLen = minLen - offsetDiff; if (rLen < mData.length) { System.arraycopy(mData, 0, mData, -offsetDiff, minLen); Arrays.fill(mData, 0, -offsetDiff, 0); } else { int[] r = new int[rLen]; System.arraycopy(mData, 0, r, -offsetDiff, minLen); minuend.data = mData = r; } minuend.offset = subtrahend.offset; minuend.nWords = minLen = rLen; offsetDiff = 0; } long borrow = 0L; int mIndex = offsetDiff; for (int sIndex = 0; sIndex < subLen && mIndex < minLen; sIndex++, mIndex++) { long diff = (mData[mIndex] & LONG_MASK) - (sData[sIndex] & LONG_MASK) + borrow; mData[mIndex] = (int) diff; borrow = diff >> 32; // signed shift } for (; borrow != 0 && mIndex < minLen; mIndex++) { long diff = (mData[mIndex] & LONG_MASK) + borrow; mData[mIndex] = (int) diff; borrow = diff >> 32; // signed shift } assert borrow == 0L : borrow; // borrow out of subtract, // result should be positive minuend.trimLeadingZeros(); return minuend; } /** * Subtracts the supplied FDBigInteger subtrahend from this * FDBigInteger. Assert that the result is positive. * If the this(minuend) is immutable, store the result in subtrahend. * If subtrahend is immutable a new FDBigInteger is created. * * @param subtrahend The FDBigInteger to be subtracted. * @return This FDBigInteger less the subtrahend. */ /*@ @ requires subtrahend.isImmutable; @ requires this.value() >= subtrahend.value(); @ assignable \nothing; @ ensures \result.value() == \old(this.value() - subtrahend.value()); @ @ also @ @ requires !subtrahend.isImmutable; @ requires this.value() >= subtrahend.value(); @ assignable subtrahend.nWords, subtrahend.offset, subtrahend.data, subtrahend.data[*]; @ ensures \result == subtrahend; @ ensures \result.value() == \old(this.value() - subtrahend.value()); @*/ public FDBigInteger rightInplaceSub(FDBigInteger subtrahend) { assert this.size() >= subtrahend.size() : "result should be positive"; FDBigInteger minuend = this; if (subtrahend.isImmutable) { subtrahend = new FDBigInteger(subtrahend.data.clone(), subtrahend.offset); } int offsetDiff = minuend.offset - subtrahend.offset; int[] sData = subtrahend.data; int[] mData = minuend.data; int subLen = subtrahend.nWords; int minLen = minuend.nWords; if (offsetDiff < 0) { int rLen = minLen; if (rLen < sData.length) { System.arraycopy(sData, 0, sData, -offsetDiff, subLen); Arrays.fill(sData, 0, -offsetDiff, 0); } else { int[] r = new int[rLen]; System.arraycopy(sData, 0, r, -offsetDiff, subLen); subtrahend.data = sData = r; } subtrahend.offset = minuend.offset; subLen -= offsetDiff; offsetDiff = 0; } else { int rLen = minLen + offsetDiff; if (rLen >= sData.length) { subtrahend.data = sData = Arrays.copyOf(sData, rLen); } } //@ assert minuend == this && minuend.value() == \old(this.value()); //@ assert mData == minuend.data && minLen == minuend.nWords; //@ assert subtrahend.offset + subtrahend.data.length >= minuend.size(); //@ assert sData == subtrahend.data; //@ assert AP(subtrahend.data, subtrahend.data.length) << subtrahend.offset == \old(subtrahend.value()); //@ assert subtrahend.offset == Math.min(\old(this.offset), minuend.offset); //@ assert offsetDiff == minuend.offset - subtrahend.offset; //@ assert 0 <= offsetDiff && offsetDiff + minLen <= sData.length; int sIndex = 0; long borrow = 0L; for (; sIndex < offsetDiff; sIndex++) { long diff = 0L - (sData[sIndex] & LONG_MASK) + borrow; sData[sIndex] = (int) diff; borrow = diff >> 32; // signed shift } //@ assert sIndex == offsetDiff; for (int mIndex = 0; mIndex < minLen; sIndex++, mIndex++) { //@ assert sIndex == offsetDiff + mIndex; long diff = (mData[mIndex] & LONG_MASK) - (sData[sIndex] & LONG_MASK) + borrow; sData[sIndex] = (int) diff; borrow = diff >> 32; // signed shift } assert borrow == 0L : borrow; // borrow out of subtract, // result should be positive subtrahend.nWords = sIndex; subtrahend.trimLeadingZeros(); return subtrahend; } /** * Determines whether all elements of an array are zero for all indices less * than a given index. * * @param a The array to be examined. * @param from The index strictly below which elements are to be examined. * @return Zero if all elements in range are zero, 1 otherwise. */ /*@ @ requires 0 <= from && from <= a.length; @ ensures \result == (AP(a, from) == 0 ? 0 : 1); @*/ private /*@ pure @*/ static int checkZeroTail(int[] a, int from) { while (from > 0) { if (a[--from] != 0) { return 1; } } return 0; } /** * Compares the parameter with this FDBigInteger. Returns an * integer accordingly as: *
{@code
     * > 0: this > other
     *   0: this == other
     * < 0: this < other
     * }
* * @param other The FDBigInteger to compare. * @return A negative value, zero, or a positive value according to the * result of the comparison. */ /*@ @ ensures \result == (this.value() < other.value() ? -1 : this.value() > other.value() ? +1 : 0); @*/ public /*@ pure @*/ int cmp(FDBigInteger other) { int aSize = nWords + offset; int bSize = other.nWords + other.offset; if (aSize > bSize) { return 1; } else if (aSize < bSize) { return -1; } int aLen = nWords; int bLen = other.nWords; while (aLen > 0 && bLen > 0) { int a = data[--aLen]; int b = other.data[--bLen]; if (a != b) { return ((a & LONG_MASK) < (b & LONG_MASK)) ? -1 : 1; } } if (aLen > 0) { return checkZeroTail(data, aLen); } if (bLen > 0) { return -checkZeroTail(other.data, bLen); } return 0; } /** * Compares this FDBigInteger with * 5p5 * 2p2. * Returns an integer accordingly as: *
{@code
     * > 0: this > other
     *   0: this == other
     * < 0: this < other
     * }
* @param p5 The exponent of the power-of-five factor. * @param p2 The exponent of the power-of-two factor. * @return A negative value, zero, or a positive value according to the * result of the comparison. */ /*@ @ requires p5 >= 0 && p2 >= 0; @ ensures \result == (this.value() < pow52(p5, p2) ? -1 : this.value() > pow52(p5, p2) ? +1 : 0); @*/ public /*@ pure @*/ int cmpPow52(int p5, int p2) { if (p5 == 0) { int wordcount = p2 >> 5; int bitcount = p2 & 0x1f; int size = this.nWords + this.offset; if (size > wordcount + 1) { return 1; } else if (size < wordcount + 1) { return -1; } int a = this.data[this.nWords -1]; int b = 1 << bitcount; if (a != b) { return ( (a & LONG_MASK) < (b & LONG_MASK)) ? -1 : 1; } return checkZeroTail(this.data, this.nWords - 1); } return this.cmp(big5pow(p5).leftShift(p2)); } /** * Compares this FDBigInteger with x + y. Returns a * value according to the comparison as: *
{@code
     * -1: this <  x + y
     *  0: this == x + y
     *  1: this >  x + y
     * }
* @param x The first addend of the sum to compare. * @param y The second addend of the sum to compare. * @return -1, 0, or 1 according to the result of the comparison. */ /*@ @ ensures \result == (this.value() < x.value() + y.value() ? -1 : this.value() > x.value() + y.value() ? +1 : 0); @*/ public /*@ pure @*/ int addAndCmp(FDBigInteger x, FDBigInteger y) { FDBigInteger big; FDBigInteger small; int xSize = x.size(); int ySize = y.size(); int bSize; int sSize; if (xSize >= ySize) { big = x; small = y; bSize = xSize; sSize = ySize; } else { big = y; small = x; bSize = ySize; sSize = xSize; } int thSize = this.size(); if (bSize == 0) { return thSize == 0 ? 0 : 1; } if (sSize == 0) { return this.cmp(big); } if (bSize > thSize) { return -1; } if (bSize + 1 < thSize) { return 1; } long top = (big.data[big.nWords - 1] & LONG_MASK); if (sSize == bSize) { top += (small.data[small.nWords - 1] & LONG_MASK); } if ((top >>> 32) == 0) { if (((top + 1) >>> 32) == 0) { // good case - no carry extension if (bSize < thSize) { return 1; } // here sum.nWords == this.nWords long v = (this.data[this.nWords - 1] & LONG_MASK); if (v < top) { return -1; } if (v > top + 1) { return 1; } } } else { // (top>>>32)!=0 guaranteed carry extension if (bSize + 1 > thSize) { return -1; } // here sum.nWords == this.nWords top >>>= 32; long v = (this.data[this.nWords - 1] & LONG_MASK); if (v < top) { return -1; } if (v > top + 1) { return 1; } } return this.cmp(big.add(small)); } /** * Makes this FDBigInteger immutable. */ /*@ @ assignable this.isImmutable; @ ensures this.isImmutable; @*/ public void makeImmutable() { this.isImmutable = true; } /** * Multiplies this FDBigInteger by an integer. * * @param i The factor by which to multiply this FDBigInteger. * @return This FDBigInteger multiplied by an integer. */ /*@ @ requires this.value() == 0; @ assignable \nothing; @ ensures \result == this; @ @ also @ @ requires this.value() != 0; @ assignable \nothing; @ ensures \result.value() == \old(this.value() * UNSIGNED(i)); @*/ private FDBigInteger mult(int i) { if (this.nWords == 0) { return this; } int[] r = new int[nWords + 1]; mult(data, nWords, i, r); return new FDBigInteger(r, offset); } /** * Multiplies this FDBigInteger by another FDBigInteger. * * @param other The FDBigInteger factor by which to multiply. * @return The product of this and the parameter FDBigIntegers. */ /*@ @ requires this.value() == 0; @ assignable \nothing; @ ensures \result == this; @ @ also @ @ requires this.value() != 0 && other.value() == 0; @ assignable \nothing; @ ensures \result == other; @ @ also @ @ requires this.value() != 0 && other.value() != 0; @ assignable \nothing; @ ensures \result.value() == \old(this.value() * other.value()); @*/ private FDBigInteger mult(FDBigInteger other) { if (this.nWords == 0) { return this; } if (this.size() == 1) { return other.mult(data[0]); } if (other.nWords == 0) { return other; } if (other.size() == 1) { return this.mult(other.data[0]); } int[] r = new int[nWords + other.nWords]; mult(this.data, this.nWords, other.data, other.nWords, r); return new FDBigInteger(r, this.offset + other.offset); } /** * Adds another FDBigInteger to this FDBigInteger. * * @param other The FDBigInteger to add. * @return The sum of the FDBigIntegers. */ /*@ @ assignable \nothing; @ ensures \result.value() == \old(this.value() + other.value()); @*/ private FDBigInteger add(FDBigInteger other) { FDBigInteger big, small; int bigLen, smallLen; int tSize = this.size(); int oSize = other.size(); if (tSize >= oSize) { big = this; bigLen = tSize; small = other; smallLen = oSize; } else { big = other; bigLen = oSize; small = this; smallLen = tSize; } int[] r = new int[bigLen + 1]; int i = 0; long carry = 0L; for (; i < smallLen; i++) { carry += (i < big.offset ? 0L : (big.data[i - big.offset] & LONG_MASK) ) + ((i < small.offset ? 0L : (small.data[i - small.offset] & LONG_MASK))); r[i] = (int) carry; carry >>= 32; // signed shift. } for (; i < bigLen; i++) { carry += (i < big.offset ? 0L : (big.data[i - big.offset] & LONG_MASK) ); r[i] = (int) carry; carry >>= 32; // signed shift. } r[bigLen] = (int) carry; return new FDBigInteger(r, 0); } /** * Multiplies a FDBigInteger by an int and adds another int. The * result is computed in place. This method is intended only to be invoked * from * * FDBigInteger(long lValue, char[] digits, int kDigits, int nDigits) * . * * @param iv The factor by which to multiply this FDBigInteger. * @param addend The value to add to the product of this * FDBigInteger and iv. */ /*@ @ requires this.value()*UNSIGNED(iv) + UNSIGNED(addend) < ((\bigint)1) << ((this.data.length + this.offset)*32); @ assignable this.data[*]; @ ensures this.value() == \old(this.value()*UNSIGNED(iv) + UNSIGNED(addend)); @*/ private /*@ helper @*/ void multAddMe(int iv, int addend) { long v = iv & LONG_MASK; // unroll 0th iteration, doing addition. long p = v * (data[0] & LONG_MASK) + (addend & LONG_MASK); data[0] = (int) p; p >>>= 32; for (int i = 1; i < nWords; i++) { p += v * (data[i] & LONG_MASK); data[i] = (int) p; p >>>= 32; } if (p != 0L) { data[nWords++] = (int) p; // will fail noisily if illegal! } } // // original doc: // // do this -=q*S // returns borrow // /** * Multiplies the parameters and subtracts them from this * FDBigInteger. * * @param q The integer parameter. * @param S The FDBigInteger parameter. * @return this - q*S. */ /*@ @ ensures nWords == 0 ==> offset == 0; @ ensures nWords > 0 ==> data[nWords - 1] != 0; @*/ /*@ @ requires 0 < q && q <= (1L << 31); @ requires data != null; @ requires 0 <= nWords && nWords <= data.length && offset >= 0; @ requires !this.isImmutable; @ requires this.size() == S.size(); @ requires this != S; @ assignable this.nWords, this.offset, this.data, this.data[*]; @ ensures -q <= \result && \result <= 0; @ ensures this.size() == \old(this.size()); @ ensures this.value() + (\result << (this.size()*32)) == \old(this.value() - q*S.value()); @ ensures this.offset == \old(Math.min(this.offset, S.offset)); @ ensures \old(this.offset <= S.offset) ==> this.nWords == \old(this.nWords); @ ensures \old(this.offset <= S.offset) ==> this.offset == \old(this.offset); @ ensures \old(this.offset <= S.offset) ==> this.data == \old(this.data); @ @ also @ @ requires q == 0; @ assignable \nothing; @ ensures \result == 0; @*/ private /*@ helper @*/ long multDiffMe(long q, FDBigInteger S) { long diff = 0L; if (q != 0) { int deltaSize = S.offset - this.offset; if (deltaSize >= 0) { int[] sd = S.data; int[] td = this.data; for (int sIndex = 0, tIndex = deltaSize; sIndex < S.nWords; sIndex++, tIndex++) { diff += (td[tIndex] & LONG_MASK) - q * (sd[sIndex] & LONG_MASK); td[tIndex] = (int) diff; diff >>= 32; // N.B. SIGNED shift. } } else { deltaSize = -deltaSize; int[] rd = new int[nWords + deltaSize]; int sIndex = 0; int rIndex = 0; int[] sd = S.data; for (; rIndex < deltaSize && sIndex < S.nWords; sIndex++, rIndex++) { diff -= q * (sd[sIndex] & LONG_MASK); rd[rIndex] = (int) diff; diff >>= 32; // N.B. SIGNED shift. } int tIndex = 0; int[] td = this.data; for (; sIndex < S.nWords; sIndex++, tIndex++, rIndex++) { diff += (td[tIndex] & LONG_MASK) - q * (sd[sIndex] & LONG_MASK); rd[rIndex] = (int) diff; diff >>= 32; // N.B. SIGNED shift. } this.nWords += deltaSize; this.offset -= deltaSize; this.data = rd; } } return diff; } /** * Multiplies by 10 a big integer represented as an array. The final carry * is returned. * * @param src The array representation of the big integer. * @param srcLen The number of elements of src to use. * @param dst The product array. * @return The final carry of the multiplication. */ /*@ @ requires src.length >= srcLen && dst.length >= srcLen; @ assignable dst[0 .. srcLen - 1]; @ ensures 0 <= \result && \result < 10; @ ensures AP(dst, srcLen) + (\result << (srcLen*32)) == \old(AP(src, srcLen) * 10); @*/ private static int multAndCarryBy10(int[] src, int srcLen, int[] dst) { long carry = 0; for (int i = 0; i < srcLen; i++) { long product = (src[i] & LONG_MASK) * 10L + carry; dst[i] = (int) product; carry = product >>> 32; } return (int) carry; } /** * Multiplies by a constant value a big integer represented as an array. * The constant factor is an int. * * @param src The array representation of the big integer. * @param srcLen The number of elements of src to use. * @param value The constant factor by which to multiply. * @param dst The product array. */ /*@ @ requires src.length >= srcLen && dst.length >= srcLen + 1; @ assignable dst[0 .. srcLen]; @ ensures AP(dst, srcLen + 1) == \old(AP(src, srcLen) * UNSIGNED(value)); @*/ private static void mult(int[] src, int srcLen, int value, int[] dst) { long val = value & LONG_MASK; long carry = 0; for (int i = 0; i < srcLen; i++) { long product = (src[i] & LONG_MASK) * val + carry; dst[i] = (int) product; carry = product >>> 32; } dst[srcLen] = (int) carry; } /** * Multiplies by a constant value a big integer represented as an array. * The constant factor is a long represent as two ints. * * @param src The array representation of the big integer. * @param srcLen The number of elements of src to use. * @param v0 The lower 32 bits of the long factor. * @param v1 The upper 32 bits of the long factor. * @param dst The product array. */ /*@ @ requires src != dst; @ requires src.length >= srcLen && dst.length >= srcLen + 2; @ assignable dst[0 .. srcLen + 1]; @ ensures AP(dst, srcLen + 2) == \old(AP(src, srcLen) * (UNSIGNED(v0) + (UNSIGNED(v1) << 32))); @*/ private static void mult(int[] src, int srcLen, int v0, int v1, int[] dst) { long v = v0 & LONG_MASK; long carry = 0; for (int j = 0; j < srcLen; j++) { long product = v * (src[j] & LONG_MASK) + carry; dst[j] = (int) product; carry = product >>> 32; } dst[srcLen] = (int) carry; v = v1 & LONG_MASK; carry = 0; for (int j = 0; j < srcLen; j++) { long product = (dst[j + 1] & LONG_MASK) + v * (src[j] & LONG_MASK) + carry; dst[j + 1] = (int) product; carry = product >>> 32; } dst[srcLen + 1] = (int) carry; } // Fails assertion for negative exponent. /** * Computes 5 raised to a given power. * * @param p The exponent of 5. * @return 5p. */ private static FDBigInteger big5pow(int p) { assert p >= 0 : p; // negative power of 5 if (p < MAX_FIVE_POW) { return POW_5_CACHE[p]; } return big5powRec(p); } // slow path /** * Computes 5 raised to a given power. * * @param p The exponent of 5. * @return 5p. */ private static FDBigInteger big5powRec(int p) { if (p < MAX_FIVE_POW) { return POW_5_CACHE[p]; } // construct the value. // recursively. int q, r; // in order to compute 5^p, // compute its square root, 5^(p/2) and square. // or, let q = p / 2, r = p -q, then // 5^p = 5^(q+r) = 5^q * 5^r q = p >> 1; r = p - q; FDBigInteger bigq = big5powRec(q); if (r < SMALL_5_POW.length) { return bigq.mult(SMALL_5_POW[r]); } else { return bigq.mult(big5powRec(r)); } } // for debugging ... /** * Converts this FDBigInteger to a hexadecimal string. * * @return The hexadecimal string representation. */ public String toHexString(){ if(nWords ==0) { return "0"; } StringBuilder sb = new StringBuilder((nWords +offset)*8); for(int i= nWords -1; i>=0; i--) { String subStr = Integer.toHexString(data[i]); for(int j = subStr.length(); j<8; j++) { sb.append('0'); } sb.append(subStr); } for(int i=offset; i>0; i--) { sb.append("00000000"); } return sb.toString(); } // for debugging ... /** * Converts this FDBigInteger to a BigInteger. * * @return The BigInteger representation. */ public BigInteger toBigInteger() { byte[] magnitude = new byte[nWords * 4 + 1]; for (int i = 0; i < nWords; i++) { int w = data[i]; magnitude[magnitude.length - 4 * i - 1] = (byte) w; magnitude[magnitude.length - 4 * i - 2] = (byte) (w >> 8); magnitude[magnitude.length - 4 * i - 3] = (byte) (w >> 16); magnitude[magnitude.length - 4 * i - 4] = (byte) (w >> 24); } return new BigInteger(magnitude).shiftLeft(offset * 32); } // for debugging ... /** * Converts this FDBigInteger to a string. * * @return The string representation. */ @Override public String toString(){ return toBigInteger().toString(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy