BigInteger toBigInteger()

in commons-statistics-descriptive/src/main/java/org/apache/commons/statistics/descriptive/Int128.java [146:198]


    BigInteger toBigInteger() {
        long h = hi;
        long l = lo;
        // Special cases
        if (h == 0) {
            return BigInteger.valueOf(l);
        }
        if (l == 0) {
            return BigInteger.valueOf(h).shiftLeft(64);
        }

        // The representation is 2^64 * hi64 + lo64.
        // Here we avoid evaluating the addition:
        // BigInteger.valueOf(l).add(BigInteger.valueOf(h).shiftLeft(64))
        // It is faster to create from bytes.
        // BigInteger bytes are an unsigned integer in BigEndian format, plus a sign.
        // If both values are positive we can use the values unchanged.
        // Otherwise selective negation is used to create a positive magnitude
        // and we track the sign.
        // Note: Negation of -2^63 is valid to create an unsigned 2^63.

        int sign = 1;
        if ((h ^ l) < 0) {
            // Opposite signs and lo64 is not zero.
            // The lo64 bits are an adjustment to the magnitude of hi64
            // to make it smaller.
            // Here we rearrange to [2^64 * (hi64-1)] + [2^64 - lo64].
            // The second term [2^64 - lo64] can use lo64 as an unsigned 64-bit integer.
            // The first term [2^64 * (hi64-1)] does not work if low is zero.
            // It would work if zero was detected and we carried the overflow
            // bit up to h to make it equal to: (h - 1) + 1 == h.
            // Instead lo64 == 0 is handled as a special case above.

            if (h >= 0) {
                // Treat (unchanged) low as an unsigned add
                h = h - 1;
            } else {
                // As above with negation
                h = ~h; // -h - 1
                l = -l;
                sign = -1;
            }
        } else if (h < 0) {
            // Invert negative values to create the equivalent positive magnitude.
            h = -h;
            l = -l;
            sign = -1;
        }

        return new BigInteger(sign,
            ByteBuffer.allocate(Long.BYTES * 2)
                .putLong(h).putLong(l).array());
    }