/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jruby.ext.bigdecimal;
import java.math.BigInteger;
// NOTE: from Android's sources
// https://android.googlesource.com/platform/libcore/+/refs/heads/master/luni/src/main/java/java/math/Multiplication.java
Static library that provides all multiplication of BigInteger
methods. /**
* Static library that provides all multiplication of {@link BigInteger} methods.
*/
class Multiplication {
Just to denote that this class can't be instantiated. /** Just to denote that this class can't be instantiated. */
private Multiplication() {}
static final BigInteger FIVE = BigInteger.valueOf(5);
An array with the first powers of ten in BigInteger
version. (10^0,10^1,...,10^31
) /**
* An array with the first powers of ten in {@code BigInteger} version.
* ({@code 10^0,10^1,...,10^31})
*/
static final BigInteger[] bigTenPows = new BigInteger[32];
static {
bigTenPows[0] = BigInteger.ONE;
bigTenPows[1] = BigInteger.TEN;
bigTenPows[2] = BigInteger.valueOf(100);
bigTenPows[3] = BigInteger.valueOf(1000);
bigTenPows[4] = BigInteger.valueOf(10000);
bigTenPows[5] = BigInteger.valueOf(100000);
bigTenPows[6] = BigInteger.valueOf(1000000);
bigTenPows[7] = BigInteger.valueOf(10000000);
bigTenPows[8] = BigInteger.valueOf(100000000);
bigTenPows[9] = BigInteger.valueOf(1000000000);
bigTenPows[10] = BigInteger.valueOf(10000000000L);
bigTenPows[11] = BigInteger.valueOf(100000000000L);
bigTenPows[12] = BigInteger.valueOf(1000000000000L);
bigTenPows[13] = BigInteger.valueOf(10000000000000L);
bigTenPows[14] = BigInteger.valueOf(100000000000000L);
bigTenPows[15] = BigInteger.valueOf(1000000000000000L);
bigTenPows[16] = BigInteger.valueOf(10000000000000000L);
bigTenPows[17] = BigInteger.valueOf(100000000000000000L);
bigTenPows[18] = BigInteger.valueOf(1000000000000000000L);
for (int i=19; i < bigTenPows.length; i++) {
bigTenPows[i] = bigTenPows[i - 1].multiply(BigInteger.TEN);
}
}
It calculates a power of ten, which exponent could be out of 32-bit range. Note that internally this method will be used in the worst case with an exponent equals to: Integer.MAX_VALUE - Integer.MIN_VALUE
. Params: - exp – the exponent of power of ten, it must be positive.
Returns: a BigInteger
with value 10<sup>exp</sup>
.
/**
* It calculates a power of ten, which exponent could be out of 32-bit range.
* Note that internally this method will be used in the worst case with
* an exponent equals to: {@code Integer.MAX_VALUE - Integer.MIN_VALUE}.
* @param exp the exponent of power of ten, it must be positive.
* @return a {@code BigInteger} with value {@code 10<sup>exp</sup>}.
*/
static BigInteger powerOf10(long exp) {
// PRE: exp >= 0
int intExp = (int)exp;
// "SMALL POWERS"
if (exp < bigTenPows.length) {
// The largest power that fit in 'long' type
return bigTenPows[intExp];
} else if (exp <= 50) {
// To calculate: 10^exp
return BigInteger.TEN.pow(intExp);
}
BigInteger res;
try {
// "LARGE POWERS"
if (exp <= Integer.MAX_VALUE) {
// To calculate: 5^exp * 2^exp
res = FIVE.pow(intExp).shiftLeft(intExp);
} else {
/*
* "HUGE POWERS"
*
* This branch probably won't be executed since the power of ten is too
* big.
*/
// To calculate: 5^exp
BigInteger powerOfFive = FIVE.pow(Integer.MAX_VALUE);
res = powerOfFive;
long longExp = exp - Integer.MAX_VALUE;
intExp = (int) (exp % Integer.MAX_VALUE);
while (longExp > Integer.MAX_VALUE) {
res = res.multiply(powerOfFive);
longExp -= Integer.MAX_VALUE;
}
res = res.multiply(FIVE.pow(intExp));
// To calculate: 5^exp << exp
res = res.shiftLeft(Integer.MAX_VALUE);
longExp = exp - Integer.MAX_VALUE;
while (longExp > Integer.MAX_VALUE) {
res = res.shiftLeft(Integer.MAX_VALUE);
longExp -= Integer.MAX_VALUE;
}
res = res.shiftLeft(intExp);
}
} catch (OutOfMemoryError error) {
throw new ArithmeticException(error.getMessage());
}
return res;
}
}