mailiverse/gwt/jre/java/math/Elementary.java
Timothy Prepscius 55b423621f adds GWT code
2013-07-21 12:49:20 -04:00

458 lines
14 KiB
Java

/*
* Copyright 2009 Google Inc.
*
* Licensed 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.
*/
/*
* 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.
*
* INCLUDES MODIFICATIONS BY RICHARD ZSCHECH AS WELL AS GOOGLE.
*/
package java.math;
/**
* Static library that provides the basic arithmetic mutable operations for
* {@link BigInteger}. The operations provided are listed below. <ul
* type="circle"> <li>Addition.</li> <li>Subtraction.</li> <li>Comparison.</li>
* </ul> In addition to this, some <i><b>Inplace</b></i> (mutable) methods are
* provided.
*/
class Elementary {
/**
* @see BigInteger#add(BigInteger) .
* @param op1
* @param op2
* @return
*/
static BigInteger add(BigInteger op1, BigInteger op2) {
int resDigits[];
int resSign;
int op1Sign = op1.sign;
int op2Sign = op2.sign;
if (op1Sign == 0) {
return op2;
}
if (op2Sign == 0) {
return op1;
}
int op1Len = op1.numberLength;
int op2Len = op2.numberLength;
if (op1Len + op2Len == 2) {
long a = (op1.digits[0] & 0xFFFFFFFFL);
long b = (op2.digits[0] & 0xFFFFFFFFL);
long res;
int valueLo;
int valueHi;
if (op1Sign == op2Sign) {
res = a + b;
valueLo = (int) res;
valueHi = (int) (res >>> 32);
return ((valueHi == 0) ? new BigInteger(op1Sign, valueLo)
: new BigInteger(op1Sign, 2, new int[] {valueLo, valueHi}));
}
return BigInteger.valueOf((op1Sign < 0) ? (b - a) : (a - b));
} else if (op1Sign == op2Sign) {
resSign = op1Sign;
// an augend should not be shorter than addend
resDigits = (op1Len >= op2Len) ? add(op1.digits, op1Len, op2.digits,
op2Len) : add(op2.digits, op2Len, op1.digits, op1Len);
} else { // signs are different
int cmp = ((op1Len != op2Len) ? ((op1Len > op2Len) ? 1 : -1)
: compareArrays(op1.digits, op2.digits, op1Len));
if (cmp == BigInteger.EQUALS) {
return BigInteger.ZERO;
}
// a minuend should not be shorter than subtrahend
if (cmp == BigInteger.GREATER) {
resSign = op1Sign;
resDigits = subtract(op1.digits, op1Len, op2.digits, op2Len);
} else {
resSign = op2Sign;
resDigits = subtract(op2.digits, op2Len, op1.digits, op1Len);
}
}
BigInteger res = new BigInteger(resSign, resDigits.length, resDigits);
res.cutOffLeadingZeroes();
return res;
}
/**
* Compares two arrays. All elements are treated as unsigned integers. The
* magnitude is the bit chain of elements in big-endian order.
*
* @param a the first array
* @param b the second array
* @param size the size of arrays
* @return 1 if a > b, -1 if a < b, 0 if a == b
*/
static int compareArrays(final int[] a, final int[] b, final int size) {
int i;
for (i = size - 1; (i >= 0) && (a[i] == b[i]); i--) {
// empty
}
return ((i < 0) ? BigInteger.EQUALS
: (a[i] & 0xFFFFFFFFL) < (b[i] & 0xFFFFFFFFL) ? BigInteger.LESS
: BigInteger.GREATER);
}
/**
* Same as @link #inplaceAdd(BigInteger, BigInteger), but without the
* restriction of non-positive values.
*
* @param op1 any number
* @param op2 any number
*/
static void completeInPlaceAdd(BigInteger op1, BigInteger op2) {
if (op1.sign == 0) {
System.arraycopy(op2.digits, 0, op1.digits, 0, op2.numberLength);
} else if (op2.sign == 0) {
return;
} else if (op1.sign == op2.sign) {
add(op1.digits, op1.digits, op1.numberLength, op2.digits,
op2.numberLength);
} else {
int sign = unsignedArraysCompare(op1.digits, op2.digits,
op1.numberLength, op2.numberLength);
if (sign > 0) {
subtract(op1.digits, op1.digits, op1.numberLength, op2.digits,
op2.numberLength);
} else {
inverseSubtract(op1.digits, op1.digits, op1.numberLength, op2.digits,
op2.numberLength);
op1.sign = -op1.sign;
}
}
op1.numberLength = Math.max(op1.numberLength, op2.numberLength) + 1;
op1.cutOffLeadingZeroes();
op1.unCache();
}
/**
* Same as @link #inplaceSubtract(BigInteger, BigInteger), but without the
* restriction of non-positive values.
*
* @param op1 should have enough space to save the result
* @param op2
*/
static void completeInPlaceSubtract(BigInteger op1, BigInteger op2) {
int resultSign = op1.compareTo(op2);
if (op1.sign == 0) {
System.arraycopy(op2.digits, 0, op1.digits, 0, op2.numberLength);
op1.sign = -op2.sign;
} else if (op1.sign != op2.sign) {
add(op1.digits, op1.digits, op1.numberLength, op2.digits,
op2.numberLength);
op1.sign = resultSign;
} else {
int sign = unsignedArraysCompare(op1.digits, op2.digits,
op1.numberLength, op2.numberLength);
if (sign > 0) {
subtract(op1.digits, op1.digits, op1.numberLength, op2.digits,
op2.numberLength); // op1 = op1 - op2
// op1.sign remains equal
} else {
inverseSubtract(op1.digits, op1.digits, op1.numberLength, op2.digits,
op2.numberLength); // op1 = op2 - op1
op1.sign = -op1.sign;
}
}
op1.numberLength = Math.max(op1.numberLength, op2.numberLength) + 1;
op1.cutOffLeadingZeroes();
op1.unCache();
}
/**
* Performs {@code op1 += op2}. {@code op1} must have enough place to store
* the result (i.e. {@code op1.bitLength() >= op2.bitLength()}). Both should
* be positive (i.e. {@code op1 >= op2}).
*
* @param op1 the input minuend, and the output result.
* @param op2 the addend
*/
static void inplaceAdd(BigInteger op1, BigInteger op2) {
// PRE: op1 >= op2 > 0
add(op1.digits, op1.digits, op1.numberLength, op2.digits, op2.numberLength);
op1.numberLength = Math.min(
Math.max(op1.numberLength, op2.numberLength) + 1, op1.digits.length);
op1.cutOffLeadingZeroes();
op1.unCache();
}
/**
* Performs: {@code op1 += addend}. The number must to have place to hold a
* possible carry.
*/
static void inplaceAdd(BigInteger op1, final int addend) {
int carry = inplaceAdd(op1.digits, op1.numberLength, addend);
if (carry == 1) {
op1.digits[op1.numberLength] = 1;
op1.numberLength++;
}
op1.unCache();
}
/**
* Adds an integer value to the array of integers remembering carry.
*
* @return a possible generated carry (0 or 1)
*/
static int inplaceAdd(int a[], final int aSize, final int addend) {
long carry = addend & 0xFFFFFFFFL;
for (int i = 0; (carry != 0) && (i < aSize); i++) {
carry += a[i] & 0xFFFFFFFFL;
a[i] = (int) carry;
carry >>= 32;
}
return (int) carry;
}
/**
* Performs {@code op1 -= op2}. {@code op1} must have enough place to store
* the result (i.e. {@code op1.bitLength() >= op2.bitLength()}). Both should
* be positive (what implies that {@code op1 >= op2}).
*
* @param op1 the input minuend, and the output result.
* @param op2 the subtrahend
*/
static void inplaceSubtract(BigInteger op1, BigInteger op2) {
// PRE: op1 >= op2 > 0
subtract(op1.digits, op1.digits, op1.numberLength, op2.digits,
op2.numberLength);
op1.cutOffLeadingZeroes();
op1.unCache();
}
/**
* @see BigInteger#subtract(BigInteger) .
* @param op1
* @param op2
* @return
*/
static BigInteger subtract(BigInteger op1, BigInteger op2) {
int resSign;
int resDigits[];
int op1Sign = op1.sign;
int op2Sign = op2.sign;
if (op2Sign == 0) {
return op1;
}
if (op1Sign == 0) {
return op2.negate();
}
int op1Len = op1.numberLength;
int op2Len = op2.numberLength;
if (op1Len + op2Len == 2) {
long a = (op1.digits[0] & 0xFFFFFFFFL);
long b = (op2.digits[0] & 0xFFFFFFFFL);
if (op1Sign < 0) {
a = -a;
}
if (op2Sign < 0) {
b = -b;
}
return BigInteger.valueOf(a - b);
}
int cmp = ((op1Len != op2Len) ? ((op1Len > op2Len) ? 1 : -1)
: Elementary.compareArrays(op1.digits, op2.digits, op1Len));
if (cmp == BigInteger.LESS) {
resSign = -op2Sign;
resDigits = (op1Sign == op2Sign) ? subtract(op2.digits, op2Len,
op1.digits, op1Len) : add(op2.digits, op2Len, op1.digits, op1Len);
} else {
resSign = op1Sign;
if (op1Sign == op2Sign) {
if (cmp == BigInteger.EQUALS) {
return BigInteger.ZERO;
}
resDigits = subtract(op1.digits, op1Len, op2.digits, op2Len);
} else {
resDigits = add(op1.digits, op1Len, op2.digits, op2Len);
}
}
BigInteger res = new BigInteger(resSign, resDigits.length, resDigits);
res.cutOffLeadingZeroes();
return res;
}
/**
* Addss the value represented by {@code b} to the value represented by
* {@code a}. It is assumed the magnitude of a is not less than the magnitude
* of b.
*
* @return {@code a + b}
*/
private static int[] add(int a[], int aSize, int b[], int bSize) {
// PRE: a[] >= b[]
int res[] = new int[aSize + 1];
add(res, a, aSize, b, bSize);
return res;
}
/**
* Performs {@code res = a + b}.
*/
private static void add(int res[], int a[], int aSize, int b[], int bSize) {
// PRE: a.length < max(aSize, bSize)
int i;
long carry = (a[0] & 0xFFFFFFFFL) + (b[0] & 0xFFFFFFFFL);
res[0] = (int) carry;
carry >>= 32;
if (aSize >= bSize) {
for (i = 1; i < bSize; i++) {
carry += (a[i] & 0xFFFFFFFFL) + (b[i] & 0xFFFFFFFFL);
res[i] = (int) carry;
carry >>= 32;
}
for (; i < aSize; i++) {
carry += a[i] & 0xFFFFFFFFL;
res[i] = (int) carry;
carry >>= 32;
}
} else {
for (i = 1; i < aSize; i++) {
carry += (a[i] & 0xFFFFFFFFL) + (b[i] & 0xFFFFFFFFL);
res[i] = (int) carry;
carry >>= 32;
}
for (; i < bSize; i++) {
carry += b[i] & 0xFFFFFFFFL;
res[i] = (int) carry;
carry >>= 32;
}
}
if (carry != 0) {
res[i] = (int) carry;
}
}
/**
* Performs {@code res = b - a}.
*/
private static void inverseSubtract(int res[], int a[], int aSize, int b[],
int bSize) {
int i;
long borrow = 0;
if (aSize < bSize) {
for (i = 0; i < aSize; i++) {
borrow += (b[i] & 0xFFFFFFFFL) - (a[i] & 0xFFFFFFFFL);
res[i] = (int) borrow;
borrow >>= 32; // -1 or 0
}
for (; i < bSize; i++) {
borrow += b[i] & 0xFFFFFFFFL;
res[i] = (int) borrow;
borrow >>= 32; // -1 or 0
}
} else {
for (i = 0; i < bSize; i++) {
borrow += (b[i] & 0xFFFFFFFFL) - (a[i] & 0xFFFFFFFFL);
res[i] = (int) borrow;
borrow >>= 32; // -1 or 0
}
for (; i < aSize; i++) {
borrow -= a[i] & 0xFFFFFFFFL;
res[i] = (int) borrow;
borrow >>= 32; // -1 or 0
}
}
}
/**
* Subtracts the value represented by {@code b} from the value represented by
* {@code a}. It is assumed the magnitude of a is not less than the magnitude
* of b.
*
* @return {@code a - b}
*/
private static int[] subtract(int a[], int aSize, int b[], int bSize) {
// PRE: a[] >= b[]
int res[] = new int[aSize];
subtract(res, a, aSize, b, bSize);
return res;
}
/**
* Performs {@code res = a - b}. It is assumed the magnitude of a is not less
* than the magnitude of b.
*/
private static void subtract(int res[], int a[], int aSize, int b[], int bSize) {
// PRE: a[] >= b[]
int i;
long borrow = 0;
for (i = 0; i < bSize; i++) {
borrow += (a[i] & 0xFFFFFFFFL) - (b[i] & 0xFFFFFFFFL);
res[i] = (int) borrow;
borrow >>= 32; // -1 or 0
}
for (; i < aSize; i++) {
borrow += a[i] & 0xFFFFFFFFL;
res[i] = (int) borrow;
borrow >>= 32; // -1 or 0
}
}
/**
* Compares two arrays, representing unsigned integer in little-endian order.
* Returns +1,0,-1 if a is - respective - greater, equal or lesser then b
*/
private static int unsignedArraysCompare(int[] a, int[] b, int aSize,
int bSize) {
if (aSize > bSize) {
return 1;
} else if (aSize < bSize) {
return -1;
} else {
int i;
for (i = aSize - 1; i >= 0 && a[i] == b[i]; i--) {
// empty
}
return i < 0 ? BigInteger.EQUALS
: ((a[i] & 0xFFFFFFFFL) < (b[i] & 0xFFFFFFFFL) ? BigInteger.LESS
: BigInteger.GREATER);
}
}
/**
* Just to denote that this class can't be instantiated.
*/
private Elementary() {
}
}