158 lines
6.4 KiB
Java
158 lines
6.4 KiB
Java
|
/*
|
||
|
* Copyright (c) 2023, 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.
|
||
|
*
|
||
|
* 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 org.openjdk.bench.java.math;
|
||
|
|
||
|
import java.math.BigInteger;
|
||
|
import java.util.Random;
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
// THIS IS NOT A BENCHMARK
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
public final class Shared {
|
||
|
|
||
|
// General note
|
||
|
// ============
|
||
|
//
|
||
|
// Isn't there a simple way to get a BigInteger of the specified number
|
||
|
// of bits of magnitude? It does not seem like it.
|
||
|
//
|
||
|
// We cannot create a BigInteger of the specified number of bytes,
|
||
|
// directly and *cheaply*. This constructor does not do what you
|
||
|
// might think it does:
|
||
|
//
|
||
|
// BigInteger(int numBits, Random rnd)
|
||
|
//
|
||
|
// The only real direct option we have is this constructor:
|
||
|
//
|
||
|
// BigInteger(int bitLength, int certainty, Random rnd)
|
||
|
//
|
||
|
// But even with certainty == 0, it is not cheap. So, create the
|
||
|
// number with the closest number of bytes and then shift right
|
||
|
// the excess bits.
|
||
|
|
||
|
private Shared() {
|
||
|
throw new AssertionError("This is a utility class");
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Creates a pair of same sign numbers x and y that minimally differ in
|
||
|
// magnitude.
|
||
|
//
|
||
|
// More formally: x.bitLength() == nBits and x.signum() == y.signum()
|
||
|
// and either
|
||
|
//
|
||
|
// * y.bitLength() == nBits, and
|
||
|
// * x.testBit(0) != y.testBit(0)
|
||
|
//
|
||
|
// or
|
||
|
//
|
||
|
// * y.bitLength() == nBits + 1
|
||
|
//
|
||
|
// By construction, such numbers are unequal to each other, but the
|
||
|
// difference in magnitude is minimal. That way, the comparison
|
||
|
// methods, such as equals and compareTo, are forced to examine
|
||
|
// the _complete_ number representation.
|
||
|
//
|
||
|
// Assumptions on BigInteger mechanics
|
||
|
// ===================================
|
||
|
//
|
||
|
// 1. bigLength() is not consulted with for short-circuiting; if it is,
|
||
|
// then we have a problem with nBits={0,1}
|
||
|
// 2. new BigInteger(0, new byte[]{0}) and new BigInteger(1, new byte[]{1})
|
||
|
// are not canonicalized to BigInteger.ZERO and BigInteger.ONE,
|
||
|
// respectively; if they are, then internal optimizations might be
|
||
|
// possible (BigInteger is not exactly a value-based class).
|
||
|
// 3. Comparison and equality are checked from the most significant bit
|
||
|
// to the least significant bit, not the other way around (for
|
||
|
// comparison it seems natural, but not for equality). If any
|
||
|
// of those are checked in the opposite direction, then the check
|
||
|
// might short-circuit.
|
||
|
//
|
||
|
public static Pair createPair(int nBits) {
|
||
|
if (nBits < 0) {
|
||
|
throw new IllegalArgumentException(String.valueOf(nBits));
|
||
|
} else if (nBits == 0) {
|
||
|
var zero = new BigInteger(nBits, new byte[0]);
|
||
|
var one = new BigInteger(/* positive */ 1, new byte[]{1});
|
||
|
return new Pair(zero, one);
|
||
|
} else if (nBits == 1) {
|
||
|
var one = new BigInteger(/* positive */ 1, new byte[]{1});
|
||
|
var two = new BigInteger(/* positive */ 1, new byte[]{2});
|
||
|
return new Pair(one, two);
|
||
|
}
|
||
|
int nBytes = (nBits + 7) / 8;
|
||
|
var r = new Random();
|
||
|
var bytes = new byte[nBytes];
|
||
|
r.nextBytes(bytes);
|
||
|
// Create a BigInteger of the exact bit length by:
|
||
|
// 1. ensuring that the most significant bit is set so that
|
||
|
// no leading zeros are truncated, and
|
||
|
// 2. explicitly specifying signum, so it's not calculated from
|
||
|
// the passed bytes, which must represent magnitude only
|
||
|
bytes[0] |= (byte) 0b1000_0000;
|
||
|
var x = new BigInteger(/* positive */ 1, bytes)
|
||
|
.shiftRight(nBytes * 8 - nBits);
|
||
|
var y = x.flipBit(0);
|
||
|
// do not rely on the assert statement in benchmark
|
||
|
if (x.bitLength() != nBits)
|
||
|
throw new AssertionError(x.bitLength() + ", " + nBits);
|
||
|
return new Pair(x, y);
|
||
|
}
|
||
|
|
||
|
public record Pair(BigInteger x, BigInteger y) {
|
||
|
public Pair {
|
||
|
if (x.signum() == -y.signum()) // if the pair comprises positive and negative
|
||
|
throw new IllegalArgumentException("x.signum()=" + x.signum()
|
||
|
+ ", y=signum()=" + y.signum());
|
||
|
if (y.bitLength() - x.bitLength() > 1)
|
||
|
throw new IllegalArgumentException("x.bitLength()=" + x.bitLength()
|
||
|
+ ", y.bitLength()=" + y.bitLength());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static BigInteger createSingle(int nBits) {
|
||
|
if (nBits < 0) {
|
||
|
throw new IllegalArgumentException(String.valueOf(nBits));
|
||
|
}
|
||
|
if (nBits == 0) {
|
||
|
return new BigInteger(nBits, new byte[0]);
|
||
|
}
|
||
|
int nBytes = (nBits + 7) / 8;
|
||
|
var r = new Random();
|
||
|
var bytes = new byte[nBytes];
|
||
|
r.nextBytes(bytes);
|
||
|
// Create a BigInteger of the exact bit length by:
|
||
|
// 1. ensuring that the most significant bit is set so that
|
||
|
// no leading zeros are truncated, and
|
||
|
// 2. explicitly specifying signum, so it's not calculated from
|
||
|
// the passed bytes, which must represent magnitude only
|
||
|
bytes[0] |= (byte) 0b1000_0000;
|
||
|
var x = new BigInteger(/* positive */ 1, bytes)
|
||
|
.shiftRight(nBytes * 8 - nBits);
|
||
|
if (x.bitLength() != nBits)
|
||
|
throw new AssertionError(x.bitLength() + ", " + nBits);
|
||
|
return x;
|
||
|
}
|
||
|
}
|