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