| /* |
| * 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() { |
| } |
| |
| } |