All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.upokecenter.numbers.EInteger Maven / Gradle / Ivy

Go to download

A Java implementation that supports arbitrary-precision binary and decimal floating-point numbers and rational numbers with arbitrary-precision components, and supports arithmetic with these numbers.

There is a newer version: 1.8.2
Show newest version
package com.upokecenter.numbers;
/*
Written in 2013-2016 by Peter O.

Parts of the code were adapted by Peter O. from
public-domain code by Wei Dai.

Parts of the GCD function adapted by Peter O.
from public domain GCD code by Christian
Stigen Larsen (http://csl.sublevel3.org).

Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
If you like this, you should donate to Peter O.
at: http://peteroupc.github.io/
 */

    /**
     * Represents an arbitrary-precision integer. (The "E" stands for "extended",
     * and has this prefix to group it with the other classes common to this
     * library, particularly EDecimal, EFloat, and ERational.) 

Instances * of this class are immutable, so they are inherently safe for use by * multiple threads. Multiple instances of this object with the same * value are interchangeable, but they should be compared using the * "Equals" method rather than the "==" operator.

Security * note

It is not recommended to implement * security-sensitive algorithms using the methods in this class, for * several reasons:

  • EInteger objects are immutable, * so they can't be modified, and the memory they occupy is not * guaranteed to be cleared in a timely fashion due to garbage * collection. This is relevant for applications that use many-bit-long * numbers as secret parameters.
  • The methods in this class * (especially those that involve arithmetic) are not guaranteed to run * in constant time for all relevant inputs. Certain attacks that * involve encrypted communications have exploited the timing and other * aspects of such communications to derive keying material or cleartext * indirectly.

Applications should instead use dedicated * security libraries to handle big numbers in security-sensitive * algorithms.

*/ public final class EInteger implements Comparable { // TODO: Investigate using 32-bit words instead of 16-bit private static final String Digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; private static final int RecursiveDivisionLimit = 40; private static final int RecursionLimit = 10; private static final int ShortMask = 0xffff; private static final int[] ValueCharToDigit = { 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 36, 36, 36, 36, 36, 36, 36, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 36, 36, 36, 36, 36, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 36, 36, 36, 36 }; private static final int[] ValueMaxSafeInts = { 1073741823, 715827881, 536870911, 429496728, 357913940, 306783377, 268435455, 238609293, 214748363, 195225785, 178956969, 165191048, 153391688, 143165575, 134217727, 126322566, 119304646, 113025454, 107374181, 102261125, 97612892, 93368853, 89478484, 85899344, 82595523, 79536430, 76695843, 74051159, 71582787, 69273665, 67108863, 65075261, 63161282, 61356674, 59652322 }; private static final EInteger ValueOne = new EInteger( 1, new short[] { 1 }, false); private static final EInteger ValueTen = new EInteger( 1, new short[] { 10 }, false); private static final EInteger ValueZero = new EInteger( 0, new short[] { 0 }, false); private final boolean negative; private final int wordCount; private final short[] words; private EInteger(int wordCount, short[] reg, boolean negative) { this.wordCount = wordCount; this.words = reg; this.negative = negative; } /** * Gets the number 1 as an arbitrary-precision integer. * @return The number 1 as an arbitrary-precision integer. */ public static EInteger getOne() { return ValueOne; } /** * Gets the number 10 as an arbitrary-precision integer. * @return The number 10 as an arbitrary-precision integer. */ public static EInteger getTen() { return ValueTen; } /** * Gets the number zero as an arbitrary-precision integer. * @return The number zero as an arbitrary-precision integer. */ public static EInteger getZero() { return ValueZero; } /** * Gets a value indicating whether this value is even. * @return {@code true} if this value is even; otherwise, {@code false} . */ public final boolean isEven() { return !this.GetUnsignedBit(0); } /** * Gets a value indicating whether this object's value is a power of two. * @return {@code true} if this object's value is a power of two; otherwise, * {@code false} . {@code true} if this object' s value is a power of * two; otherwise, {@code false} . */ public final boolean isPowerOfTwo() { if (this.negative) { return false; } return (this.wordCount == 0) ? false : (this.GetUnsignedBitLength() - 1 == this.GetLowBit()); } /** * Gets a value indicating whether this value is 0. * @return {@code true} if this value is 0; otherwise, {@code false} . */ public final boolean isZero() { return this.wordCount == 0; } /** * Gets the sign of this object's value. * @return The sign of this object' s value. */ public final int signum() { return (this.wordCount == 0) ? 0 : (this.negative ? -1 : 1); } static EInteger FromInts(int[] intWords, int count) { short[] words = new short[count << 1]; int j = 0; for (int i = 0; i < count; ++i, j += 2) { int w = intWords[i]; words[j] = ((short)w); words[j + 1] = ((short)(w >> 16)); } int newwordCount = words.length; while (newwordCount != 0 && words[newwordCount - 1] == 0) { --newwordCount; } return (newwordCount == 0) ? EInteger.FromInt32(0) : (new EInteger( newwordCount, words, false)); } /** * Initializes an arbitrary-precision integer from an array of bytes. * @param bytes A byte array consisting of the two's-complement form (see * {@link com.upokecenter.numbers.EDecimal "Forms of numbers" }) of the * arbitrary-precision integer to create. The byte array is encoded * using the following rules:
  • Positive numbers have the first * byte's highest bit cleared, and negative numbers have the bit set. *
  • The last byte contains the lowest 8-bits, the next-to-last * contains the next lowest 8 bits, and so on. For example, the number * 300 can be encoded as {@code 0x01, 0x2c} and 200 as {@code 0x00, * 0xc8} . (Note that the second example contains a set high bit in * {@code 0xc8} , so an additional 0 is added at the start to ensure * it's interpreted as positive.)
  • To encode negative numbers, * take the absolute value of the number, subtract by 1, encode the * number into bytes, and toggle each bit of each byte. Any further bits * that appear beyond the most significant bit of the number will be all * ones. For example, the number -450 can be encoded as {@code 0xfe, * 0x70} and -52869 as {@code 0xff, 0x31, 0x7b} . (Note that the second * example contains a cleared high bit in {@code 0x31, 0x7b} , so an * additional 0xff is added at the start to ensure it's interpreted as * negative.)

For little-endian, the byte order is * reversed from the byte order just discussed.

. * @param littleEndian If true, the byte order is little-endian, or * least-significant-byte first. If false, the byte order is big-endian, * or most-significant-byte first. * @return An arbitrary-precision integer. Returns 0 if the byte array's length * is 0. * @throws java.lang.NullPointerException The parameter {@code bytes} is null. */ public static EInteger FromBytes(byte[] bytes, boolean littleEndian) { if (bytes == null) { throw new NullPointerException("bytes"); } if (bytes.length == 0) { return EInteger.FromInt32(0); } int len = bytes.length; int wordLength = ((int)len + 1) >> 1; short[] newreg = new short[wordLength]; int valueJIndex = littleEndian ? len - 1 : 0; boolean numIsNegative = (bytes[valueJIndex] & 0x80) != 0; boolean newnegative = numIsNegative; int j = 0; if (!numIsNegative) { if (littleEndian) { boolean odd = (len & 1) != 0; if (odd) { --len; } for (int i = 0; i < len; i += 2, j++) { int index2 = i + 1; int nrj = ((int)bytes[i]) & 0xff; nrj |= ((int)bytes[index2]) << 8; newreg[j] = ((short)nrj); } if (odd) { newreg[len >> 1] = ((short)(((int)bytes[len]) & 0xff)); } } else { for (int i = 0; i < len; i += 2, j++) { int index = len - 1 - i; int index2 = len - 2 - i; int nrj = ((int)bytes[index]) & 0xff; if (index2 >= 0 && index2 < len) { nrj |= ((int)bytes[index2]) << 8; } newreg[j] = ((short)nrj); } } } else { for (int i = 0; i < len; i += 2, j++) { int index = littleEndian ? i : len - 1 - i; int index2 = littleEndian ? i + 1 : len - 2 - i; int nrj = ((int)bytes[index]) & 0xff; if (index2 >= 0 && index2 < len) { nrj |= ((int)bytes[index2]) << 8; } else { // sign extend the last byte nrj |= 0xff00; } newreg[j] = ((short)nrj); } for (; j < newreg.length; ++j) { newreg[j] = ((short)0xffff); // sign extend remaining words } TwosComplement(newreg, 0, (int)newreg.length); } int newwordCount = newreg.length; while (newwordCount != 0 && newreg[newwordCount - 1] == 0) { --newwordCount; } return (newwordCount == 0) ? EInteger.FromInt32(0) : (new EInteger( newwordCount, newreg, newnegative)); } /** * Converts a 32-bit signed integer to an arbitrary-precision integer. * @param intValue The parameter {@code intValue} is a 32-bit signed integer. * @return An arbitrary-precision integer with the same value as the 64-bit * number. */ public static EInteger FromInt32(int intValue) { if (intValue == 0) { return ValueZero; } if (intValue == 1) { return ValueOne; } if (intValue == 10) { return ValueTen; } short[] retreg; boolean retnegative; int retwordcount; retnegative = intValue < 0; if ((intValue >> 15) == 0) { retreg = new short[2]; if (retnegative) { intValue = -intValue; } retreg[0] = (short)(intValue & 0xffff); retwordcount = 1; } else if (intValue == Integer.MIN_VALUE) { retreg = new short[2]; retreg[0] = 0; retreg[1] = ((short)0x8000); retwordcount = 2; } else { { retreg = new short[2]; if (retnegative) { intValue = -intValue; } retreg[0] = (short)(intValue & 0xffff); intValue >>= 16; retreg[1] = (short)(intValue & 0xffff); retwordcount = (retreg[1] == 0) ? 1 : 2; } } return new EInteger(retwordcount, retreg, retnegative); } /** * Converts a 64-bit signed integer to an arbitrary-precision integer. * @param longerValue The parameter {@code longerValue} is a 64-bit signed * integer. * @return An arbitrary-precision integer with the same value as the 64-bit * number. */ public static EInteger FromInt64(long longerValue) { if (longerValue == 0) { return ValueZero; } if (longerValue == 1) { return ValueOne; } if (longerValue == 10) { return ValueTen; } short[] retreg; boolean retnegative; int retwordcount; { retnegative = longerValue < 0; if ((longerValue >> 16) == 0) { retreg = new short[1]; int intValue = (int)longerValue; if (retnegative) { intValue = -intValue; } retreg[0] = (short)(intValue & 0xffff); retwordcount = 1; } else if ((longerValue >> 31) == 0) { retreg = new short[2]; int intValue = (int)longerValue; if (retnegative) { intValue = -intValue; } retreg[0] = (short)(intValue & 0xffff); retreg[1] = (short)((intValue >> 16) & 0xffff); retwordcount = 2; } else if (longerValue == Long.MIN_VALUE) { retreg = new short[4]; retreg[0] = 0; retreg[1] = 0; retreg[2] = 0; retreg[3] = ((short)0x8000); retwordcount = 4; } else { retreg = new short[4]; long ut = longerValue; if (retnegative) { ut = -ut; } retreg[0] = (short)(ut & 0xffff); ut >>= 16; retreg[1] = (short)(ut & 0xffff); ut >>= 16; retreg[2] = (short)(ut & 0xffff); ut >>= 16; retreg[3] = (short)(ut & 0xffff); // at this point, the word count can't // be 0 (the check for 0 was already done above) retwordcount = 4; while (retwordcount != 0 && retreg[retwordcount - 1] == 0) { --retwordcount; } } } return new EInteger(retwordcount, retreg, retnegative); } /** * Converts a string to an arbitrary-precision integer in a given radix. * @param str A string described by the FromRadixSubstring method. * @param radix A base from 2 to 36. Depending on the radix, the string can use * the basic digits 0 to 9 (U + 0030 to U + 0039) and then the basic letters * A to Z (U + 0041 to U + 005A). For example, 0-9 in radix 10, and 0-9, * then A-F in radix 16. * @return An arbitrary-precision integer with the same value as the given * string. * @throws java.lang.NullPointerException The parameter {@code str} is null. */ public static EInteger FromRadixString(String str, int radix) { if (str == null) { throw new NullPointerException("str"); } return FromRadixSubstring(str, radix, 0, str.length()); } /** * Converts a portion of a string to an arbitrary-precision integer in a given * radix. * @param str A text string. The desired portion of the string must contain * only characters allowed by the given radix, except that it may start * with a minus sign ("-", U+002D) to indicate a negative number. The * desired portion is not allowed to contain white space characters, * including spaces. * @param radix A base from 2 to 36. Depending on the radix, the string can use * the basic digits 0 to 9 (U + 0030 to U + 0039) and then the basic letters * A to Z (U + 0041 to U + 005A). For example, 0-9 in radix 10, and 0-9, * then A-F in radix 16. * @param index The index of the string that starts the string portion. * @param endIndex The index of the string that ends the string portion. The * length will be index + endIndex - 1. * @return An arbitrary-precision integer with the same value as given in the * string portion. * @throws java.lang.NullPointerException The parameter {@code str} is null. * @throws java.lang.NumberFormatException The string portion is empty or in an invalid * format. * @throws IllegalArgumentException "Doesn't satisfy (endIndex - index) % 4 == * 0". */ public static EInteger FromRadixSubstring( String str, int radix, int index, int endIndex) { if (str == null) { throw new NullPointerException("str"); } if (radix < 2) { throw new IllegalArgumentException("radix (" + radix + ") is less than 2"); } if (radix > 36) { throw new IllegalArgumentException("radix (" + radix + ") is more than 36"); } if (index < 0) { throw new IllegalArgumentException("index (" + index + ") is less than " + "0"); } if (index > str.length()) { throw new IllegalArgumentException("index (" + index + ") is more than " + str.length()); } if (endIndex < 0) { throw new IllegalArgumentException("endIndex (" + endIndex + ") is less than 0"); } if (endIndex > str.length()) { throw new IllegalArgumentException("endIndex (" + endIndex + ") is more than " + str.length()); } if (endIndex < index) { throw new IllegalArgumentException("endIndex (" + endIndex + ") is less than " + index); } if (index == endIndex) { throw new NumberFormatException("No digits"); } boolean negative = false; if (str.charAt(index) == '-') { ++index; if (index == endIndex) { throw new NumberFormatException("No digits"); } negative = true; } // Skip leading zeros for (; index < endIndex; ++index) { char c = str.charAt(index); if (c != 0x30) { break; } } int effectiveLength = endIndex - index; if (effectiveLength == 0) { return EInteger.FromInt32(0); } short[] bigint; if (radix == 16) { // Special case for hexadecimal radix int leftover = effectiveLength & 3; int wordCount = effectiveLength >> 2; if (leftover != 0) { ++wordCount; } bigint = new short[wordCount]; int currentDigit = wordCount - 1; // Get most significant digits if effective // length is not divisible by 4 if (leftover != 0) { int extraWord = 0; for (int i = 0; i < leftover; ++i) { extraWord <<= 4; char c = str.charAt(index + i); int digit = (c >= 0x80) ? 36 : ValueCharToDigit[(int)c]; if (digit >= 16) { throw new NumberFormatException("Illegal character found"); } extraWord |= digit; } bigint[currentDigit] = ((short)extraWord); --currentDigit; index += leftover; } while (index < endIndex) { char c = str.charAt(index + 3); int digit = (c >= 0x80) ? 36 : ValueCharToDigit[(int)c]; if (digit >= 16) { throw new NumberFormatException("Illegal character found"); } int word = digit; c = str.charAt(index + 2); digit = (c >= 0x80) ? 36 : ValueCharToDigit[(int)c]; if (digit >= 16) { throw new NumberFormatException("Illegal character found"); } word |= digit << 4; c = str.charAt(index + 1); digit = (c >= 0x80) ? 36 : ValueCharToDigit[(int)c]; if (digit >= 16) { throw new NumberFormatException("Illegal character found"); } word |= digit << 8; c = str.charAt(index); digit = (c >= 0x80) ? 36 : ValueCharToDigit[(int)c]; if (digit >= 16) { throw new NumberFormatException("Illegal character found"); } word |= digit << 12; index += 4; bigint[currentDigit] = ((short)word); --currentDigit; } } else if (radix == 2) { // Special case for binary radix int leftover = effectiveLength & 15; int wordCount = effectiveLength >> 4; if (leftover != 0) { ++wordCount; } bigint = new short[wordCount]; int currentDigit = wordCount - 1; // Get most significant digits if effective // length is not divisible by 4 if (leftover != 0) { int extraWord = 0; for (int i = 0; i < leftover; ++i) { extraWord <<= 1; char c = str.charAt(index + i); int digit = (c == '0') ? 0 : ((c == '1') ? 1 : 2); if (digit >= 2) { throw new NumberFormatException("Illegal character found"); } extraWord |= digit; } bigint[currentDigit] = ((short)extraWord); --currentDigit; index += leftover; } while (index < endIndex) { int word = 0; int idx = index + 15; for (int i = 0; i < 16; ++i) { char c = str.charAt(idx); int digit = (c == '0') ? 0 : ((c == '1') ? 1 : 2); if (digit >= 2) { throw new NumberFormatException("Illegal character found"); } --idx; word |= digit << i; } index += 16; bigint[currentDigit] = ((short)word); --currentDigit; } } else { bigint = new short[4]; boolean haveSmallInt = true; int maxSafeInt = ValueMaxSafeInts[radix - 2]; int maxShortPlusOneMinusRadix = 65536 - radix; int smallInt = 0; for (int i = index; i < endIndex; ++i) { char c = str.charAt(i); int digit = (c >= 0x80) ? 36 : ValueCharToDigit[(int)c]; if (digit >= radix) { throw new NumberFormatException("Illegal character found"); } if (haveSmallInt && smallInt < maxSafeInt) { smallInt *= radix; smallInt += digit; } else { if (haveSmallInt) { bigint[0] = ((short)(smallInt & 0xffff)); bigint[1] = ((short)((smallInt >> 16) & 0xffff)); haveSmallInt = false; } // Multiply by the radix short carry = 0; int n = bigint.length; for (int j = 0; j < n; ++j) { int p; p = ((((int)bigint[j]) & 0xffff) * radix); int p2 = ((int)carry) & 0xffff; p = (p + p2); bigint[j] = ((short)p); carry = ((short)(p >> 16)); } if (carry != 0) { bigint = GrowForCarry(bigint, carry); } // Add the parsed digit if (digit != 0) { int d = bigint[0] & 0xffff; if (d <= maxShortPlusOneMinusRadix) { bigint[0] = ((short)(d + digit)); } else if (Increment(bigint, 0, bigint.length, (short)digit) != 0) { bigint = GrowForCarry(bigint, (short)1); } } } } if (haveSmallInt) { bigint[0] = ((short)(smallInt & 0xffff)); bigint[1] = ((short)((smallInt >> 16) & 0xffff)); } } int count = CountWords(bigint); return (count == 0) ? EInteger.FromInt32(0) : new EInteger( count, bigint, negative); } /** * Converts a string to an arbitrary-precision integer. * @param str A text string. The string must contain only basic digits 0 to 9 * (U+0030 to U+0039), except that it may start with a minus sign ("-", * U + 002D) to indicate a negative number. The string is not allowed to * contain white space characters, including spaces. * @return An arbitrary-precision integer with the same value as given in the * string. * @throws java.lang.NumberFormatException The parameter {@code str} is in an invalid * format. * @throws java.lang.NullPointerException The parameter {@code str} is null. */ public static EInteger FromString(String str) { if (str == null) { throw new NullPointerException("str"); } return FromRadixSubstring(str, 10, 0, str.length()); } /** * Converts a portion of a string to an arbitrary-precision integer. * @param str A text string. The desired portion of the string must contain * only basic digits 0 to 9 (U + 0030 to U + 0039), except that it may start * with a minus sign ("-", U+002D) to indicate a negative number. The * desired portion is not allowed to contain white space characters, * including spaces. * @param index The index of the string that starts the string portion. * @param endIndex The index of the string that ends the string portion. The * length will be index + endIndex - 1. * @return An arbitrary-precision integer with the same value as given in the * string portion. * @throws IllegalArgumentException The parameter {@code index} is less than 0, * {@code endIndex} is less than 0, or either is greater than the * string's length, or {@code endIndex} is less than {@code index} . * @throws java.lang.NullPointerException The parameter {@code str} is null. */ public static EInteger FromSubstring( String str, int index, int endIndex) { if (str == null) { throw new NullPointerException("str"); } return FromRadixSubstring(str, 10, index, endIndex); } /** * Returns the absolute value of this object's value. * @return This object's value with the sign removed. */ public EInteger Abs() { return (this.wordCount == 0 || !this.negative) ? this : new EInteger(this.wordCount, this.words, false); } /** * Adds this object and another object. * @param bigintAugend Another arbitrary-precision integer. * @return The sum of the two objects. * @throws java.lang.NullPointerException The parameter {@code bigintAugend} is * null. */ public EInteger Add(EInteger bigintAugend) { if (bigintAugend == null) { throw new NullPointerException("bigintAugend"); } if (this.wordCount == 0) { return bigintAugend; } if (bigintAugend.wordCount == 0) { return this; } short[] sumreg; if (bigintAugend.wordCount == 1 && this.wordCount == 1) { if (this.negative == bigintAugend.negative) { int intSum = (((int)this.words[0]) & 0xffff) + (((int)bigintAugend.words[0]) & 0xffff); sumreg = new short[2]; sumreg[0] = ((short)intSum); sumreg[1] = ((short)(intSum >> 16)); return new EInteger( ((intSum >> 16) == 0) ? 1 : 2, sumreg, this.negative); } else { int a = ((int)this.words[0]) & 0xffff; int b = ((int)bigintAugend.words[0]) & 0xffff; if (a == b) { return EInteger.FromInt32(0); } if (a > b) { a -= b; sumreg = new short[2]; sumreg[0] = ((short)a); return new EInteger(1, sumreg, this.negative); } b -= a; sumreg = new short[2]; sumreg[0] = ((short)b); return new EInteger(1, sumreg, !this.negative); } } if ((!this.negative) == (!bigintAugend.negative)) { // both nonnegative or both negative int addendCount = this.wordCount; int augendCount = bigintAugend.wordCount; if (augendCount <= 2 && addendCount <= 2 && (this.wordCount < 2 || (this.words[1] >> 15) == 0) && (bigintAugend.wordCount < 2 || (bigintAugend.words[1] >> 15) == 0)) { int a = ((int)this.words[0]) & 0xffff; if (this.wordCount == 2) { a |= (((int)this.words[1]) & 0xffff) << 16; } int b = ((int)bigintAugend.words[0]) & 0xffff; if (bigintAugend.wordCount == 2) { b |= (((int)bigintAugend.words[1]) & 0xffff) << 16; } a = ((int)(a + b)); sumreg = new short[2]; sumreg[0] = ((short)(a & 0xffff)); sumreg[1] = ((short)((a >> 16) & 0xffff)); int wcount = (sumreg[1] == 0) ? 1 : 2; return new EInteger(wcount, sumreg, this.negative); } if (augendCount <= 2 && addendCount <= 2) { int a = ((int)this.words[0]) & 0xffff; if (this.wordCount == 2) { a |= (((int)this.words[1]) & 0xffff) << 16; } int b = ((int)bigintAugend.words[0]) & 0xffff; if (bigintAugend.wordCount == 2) { b |= (((int)bigintAugend.words[1]) & 0xffff) << 16; } long longResult = ((long)a) & 0xffffffffL; longResult += ((long)b) & 0xffffffffL; if ((longResult >> 32) == 0) { a = ((int)longResult); sumreg = new short[2]; sumreg[0] = ((short)(a & 0xffff)); sumreg[1] = ((short)((a >> 16) & 0xffff)); int wcount = (sumreg[1] == 0) ? 1 : 2; return new EInteger(wcount, sumreg, this.negative); } } // DebugUtility.Log("" + this + " + " + bigintAugend); sumreg = new short[( int)Math.max( this.words.length, bigintAugend.words.length)]; int carry; int desiredLength = Math.max(addendCount, augendCount); if (addendCount == augendCount) { carry = AddInternal( sumreg, 0, this.words, 0, bigintAugend.words, 0, addendCount); } else if (addendCount > augendCount) { // Addend is bigger carry = AddInternal( sumreg, 0, this.words, 0, bigintAugend.words, 0, augendCount); System.arraycopy( this.words, augendCount, sumreg, augendCount, addendCount - augendCount); if (carry != 0) { carry = Increment( sumreg, augendCount, addendCount - augendCount, (short)carry); } } else { // Augend is bigger carry = AddInternal( sumreg, 0, this.words, 0, bigintAugend.words, 0, (int)addendCount); System.arraycopy( bigintAugend.words, addendCount, sumreg, addendCount, augendCount - addendCount); if (carry != 0) { carry = Increment( sumreg, addendCount, (int)(augendCount - addendCount), (short)carry); } } boolean needShorten = true; if (carry != 0) { int nextIndex = desiredLength; int len = nextIndex + 1; sumreg = CleanGrow(sumreg, len); sumreg[nextIndex] = (short)carry; needShorten = false; } int sumwordCount = CountWords(sumreg); if (sumwordCount == 0) { return EInteger.FromInt32(0); } if (needShorten) { sumreg = ShortenArray(sumreg, sumwordCount); } return new EInteger(sumwordCount, sumreg, this.negative); } EInteger minuend = this; EInteger subtrahend = bigintAugend; if (this.negative) { // this is negative, b is nonnegative minuend = bigintAugend; subtrahend = this; } // Do a subtraction int words1Size = minuend.wordCount; int words2Size = subtrahend.wordCount; boolean diffNeg = false; short borrow; short[] diffReg = new short[( int)Math.max( minuend.words.length, subtrahend.words.length)]; if (words1Size == words2Size) { if (Compare(minuend.words, 0, subtrahend.words, 0, (int)words1Size) >= 0) { // words1 is at least as high as words2 SubtractInternal( diffReg, 0, minuend.words, 0, subtrahend.words, 0, words1Size); } else { // words1 is less than words2 SubtractInternal( diffReg, 0, subtrahend.words, 0, minuend.words, 0, words1Size); diffNeg = true; // difference will be negative } } else if (words1Size > words2Size) { // words1 is greater than words2 borrow = ( short)SubtractInternal( diffReg, 0, minuend.words, 0, subtrahend.words, 0, words2Size); System.arraycopy( minuend.words, words2Size, diffReg, words2Size, words1Size - words2Size); Decrement(diffReg, words2Size, (int)(words1Size - words2Size), borrow); } else { // words1 is less than words2 borrow = ( short)SubtractInternal( diffReg, 0, subtrahend.words, 0, minuend.words, 0, words1Size); System.arraycopy( subtrahend.words, words1Size, diffReg, words1Size, words2Size - words1Size); Decrement(diffReg, words1Size, (int)(words2Size - words1Size), borrow); diffNeg = true; } int count = CountWords(diffReg); if (count == 0) { return EInteger.FromInt32(0); } diffReg = ShortenArray(diffReg, count); return new EInteger(count, diffReg, diffNeg); } /** * Converts this object's value to a 32-bit signed integer, throwing an * exception if it can't fit. * @return A 32-bit signed integer. * @throws T:java.lang.ArithmeticException This object' s value is too big to fit a * 32-bit signed integer. * @deprecated Renamed to ToInt32Checked. */ @Deprecated public int AsInt32Checked() { return this.ToInt32Checked(); } /** * Converts this object's value to a 32-bit signed integer. If the value can't * fit in a 32-bit integer, returns the lower 32 bits of this object's * two' s-complement form (see {@link com.upokecenter.numbers.EDecimal * "Forms of numbers" }) (in which case the return value might have a * different sign than this object's value). * @return A 32-bit signed integer. * @deprecated Renamed to ToInt32Unchecked. */ @Deprecated public int AsInt32Unchecked() { return this.ToInt32Unchecked(); } /** * Converts this object's value to a 64-bit signed integer, throwing an * exception if it can't fit. * @return A 64-bit signed integer. * @throws T:java.lang.ArithmeticException This object' s value is too big to fit a * 64-bit signed integer. * @deprecated Renamed to ToInt64Checked. */ @Deprecated public long AsInt64Checked() { return this.ToInt64Checked(); } /** * Converts this object's value to a 64-bit signed integer. If the value can't * fit in a 64-bit integer, returns the lower 64 bits of this object's * two' s-complement form (see {@link com.upokecenter.numbers.EDecimal * "Forms of numbers" }) (in which case the return value might have a * different sign than this object's value). * @return A 64-bit signed integer. * @deprecated Renamed to ToInt64Unchecked. */ @Deprecated public long AsInt64Unchecked() { return this.ToInt64Unchecked(); } /** * Returns whether this object's value can fit in a 32-bit signed integer. * @return {@code true} if this object's value is from -2147483648 through * 2147483647; otherwise, {@code false} . */ public boolean CanFitInInt32() { int c = this.wordCount; if (c > 2) { return false; } if (c == 2 && (this.words[1] & 0x8000) != 0) { return this.negative && this.words[1] == ((short)0x8000) && this.words[0] == 0; } return true; } /** * Returns whether this object's value can fit in a 64-bit signed integer. * @return {@code true} if this object's value is from -9223372036854775808 * through 9223372036854775807; otherwise, {@code false} . */ public boolean CanFitInInt64() { int c = this.wordCount; if (c > 4) { return false; } if (c == 4 && (this.words[3] & 0x8000) != 0) { return this.negative && this.words[3] == ((short)0x8000) && this.words[0] == 0; } return true; } /** * Compares an arbitrary-precision integer with this instance. * @param other The integer to compare to this value. * @return Zero if the values are equal; a negative number if this instance is * less, or a positive number if this instance is greater. */ public int compareTo(EInteger other) { if (other == null) { return 1; } if (this == other) { return 0; } int size = this.wordCount, tempSize = other.wordCount; int sa = size == 0 ? 0 : (this.negative ? -1 : 1); int sb = tempSize == 0 ? 0 : (other.negative ? -1 : 1); if (sa != sb) { return (sa < sb) ? -1 : 1; } if (sa == 0) { return 0; } if (size == tempSize) { if (size == 1 && this.words[0] == other.words[0]) { return 0; } else { short[] words1 = this.words; short[] words2 = other.words; while ((size--) != 0) { int an = ((int)words1[size]) & 0xffff; int bn = ((int)words2[size]) & 0xffff; if (an > bn) { return (sa > 0) ? 1 : -1; } if (an < bn) { return (sa > 0) ? -1 : 1; } } return 0; } } return ((size > tempSize) ^ (sa <= 0)) ? 1 : -1; } /** * Adds this object and another object.

EInteger result =
     * EInteger.FromString("5").Add(200);

* @param intValue The parameter {@code intValue} is a 32-bit signed integer. * @return The sum of the two objects. */ public EInteger Add(int intValue) { if (intValue == 0) { return this; } if (this.wordCount == 0) { return EInteger.FromInt32(intValue); } if (this.wordCount == 1 && intValue < 65535 && intValue >= -65535) { short[] sumreg; if (intValue > 0 && !this.negative) { int intSum = (((int)this.words[0]) & 0xffff) + intValue; sumreg = new short[2]; sumreg[0] = ((short)intSum); sumreg[1] = ((short)(intSum >> 16)); return new EInteger( ((intSum >> 16) == 0) ? 1 : 2, sumreg, this.negative); } else if (intValue < 0 && this.negative) { int intSum = (((int)this.words[0]) & 0xffff) - (intValue); sumreg = new short[2]; sumreg[0] = ((short)intSum); sumreg[1] = ((short)(intSum >> 16)); return new EInteger( ((intSum >> 16) == 0) ? 1 : 2, sumreg, this.negative); } else { int a = ((int)this.words[0]) & 0xffff; int b = Math.abs(intValue); if (a > b) { a -= b; sumreg = new short[2]; sumreg[0] = ((short)a); return new EInteger(1, sumreg, this.negative); }else if (a == b) { return EInteger.FromInt32(0); } else { b -= a; sumreg = new short[2]; sumreg[0] = ((short)b); return new EInteger(1, sumreg, !this.negative); } } } return this.Add(EInteger.FromInt32(intValue)); } /** * Subtracts an arbitrary-precision integer from this arbitrary-precision * integer. * @param intValue The parameter {@code intValue} is a 32-bit signed integer. * @return The difference of the two objects. */ public EInteger Subtract(int intValue) { return (intValue == Integer.MIN_VALUE) ? this.Subtract(EInteger.FromInt32(intValue)) : ((intValue == 0) ? this : this.Add(-intValue)); } /** * Multiplies this instance by the value of an arbitrary-precision integer * object.

EInteger result =
     * EInteger.FromString("5").Multiply(200);

* @param intValue The parameter {@code intValue} is a 32-bit signed integer. * @return The product of the two numbers. */ public EInteger Multiply(int intValue) { return this.Multiply(EInteger.FromInt32(intValue)); } /** * Divides this instance by the value of an arbitrary-precision integer. The * result is rounded down (the fractional part is discarded). Except if * the result is 0, it will be negative if this object is positive and * the other is negative, or vice versa, and will be positive if both * are positive or both are negative. * @param intValue The divisor. * @return The quotient of the two objects. * @throws ArithmeticException Attempted to divide by zero. */ public EInteger Divide(int intValue) { return this.Divide(EInteger.FromInt32(intValue)); } /** * Finds the remainder that results when this instance is divided by the value * of an arbitrary-precision integer. The remainder is the value that * remains when the absolute value of this object is divided by the * absolute value of the other object; the remainder has the same sign * (positive or negative) as this object. * @param intValue The parameter {@code intValue} is a 32-bit signed integer. * @return The remainder of the two numbers. * @throws ArithmeticException Attempted to divide by zero. * @throws java.lang.NullPointerException The parameter {@code intValue} is null. */ public EInteger Remainder(int intValue) { return this.Remainder(EInteger.FromInt32(intValue)); } /** * Compares an arbitrary-precision integer with this instance. * @param intValue The parameter {@code intValue} is a 32-bit signed integer. * @return Zero if the values are equal; a negative number if this instance is * less, or a positive number if this instance is greater. */ public int compareTo(int intValue) { return this.compareTo(EInteger.FromInt32(intValue)); } /** * Divides this instance by the value of an arbitrary-precision integer. The * result is rounded down (the fractional part is discarded). Except if * the result is 0, it will be negative if this object is positive and * the other is negative, or vice versa, and will be positive if both * are positive or both are negative. * @param bigintDivisor The divisor. * @return The quotient of the two objects. * @throws java.lang.NullPointerException The parameter {@code bigintDivisor} is * null. * @throws ArithmeticException Attempted to divide by zero. */ public EInteger Divide(EInteger bigintDivisor) { if (bigintDivisor == null) { throw new NullPointerException("bigintDivisor"); } int words1Size = this.wordCount; int words2Size = bigintDivisor.wordCount; // ---- Special cases if (words2Size == 0) { throw new ArithmeticException(); } if (words1Size < words2Size) { // dividend is less than divisor (includes case // where dividend is 0) return EInteger.FromInt32(0); } if (words1Size <= 2 && words2Size <= 2 && this.CanFitInInt32() && bigintDivisor.CanFitInInt32()) { int valueASmall = this.ToInt32Checked(); int valueBSmall = bigintDivisor.ToInt32Checked(); if (valueASmall != Integer.MIN_VALUE || valueBSmall != -1) { int result = valueASmall / valueBSmall; return EInteger.FromInt32(result); } } if (words1Size <= 4 && words2Size <= 4 && this.CanFitInInt64() && bigintDivisor.CanFitInInt64()) { long valueALong = this.ToInt64Checked(); long valueBLong = bigintDivisor.ToInt64Checked(); if (valueALong != Long.MIN_VALUE || valueBLong != -1) { long resultLong = valueALong / valueBLong; return EInteger.FromInt64(resultLong); } } short[] quotReg; int quotwordCount; if (words2Size == 1) { // divisor is small, use a fast path quotReg = new short[this.words.length]; quotwordCount = this.wordCount; FastDivide(quotReg, this.words, words1Size, bigintDivisor.words[0]); while (quotwordCount != 0 && quotReg[quotwordCount - 1] == 0) { --quotwordCount; } return ( quotwordCount != 0) ? ( new EInteger( quotwordCount, quotReg, this.negative ^ bigintDivisor.negative)) : EInteger.FromInt32(0); } // ---- General case quotReg = new short[((int)(words1Size - words2Size + 1))]; GeneralDivide( this.words, 0, this.wordCount, bigintDivisor.words, 0, bigintDivisor.wordCount, quotReg, 0, null, 0); quotwordCount = CountWords(quotReg); quotReg = ShortenArray(quotReg, quotwordCount); return ( quotwordCount != 0) ? ( new EInteger( quotwordCount, quotReg, this.negative ^ bigintDivisor.negative)) : EInteger.FromInt32(0); } private static short LinearMultiplySubtractMinuend1Bigger( short[] resultArr, int resultStart, short[] minuendArr, int minuendArrStart, int factor1, short[] factor2, int factor2Start, int factor2Count) { if (factor2Count <= 0 || (factor1 >> 16) != 0) { throw new IllegalArgumentException(); } int a = 0; int b = 0; int cc = 0; for (int i = 0; i < factor2Count; ++i) { a = ((((int)factor2[factor2Start + i]) & 0xffff) * factor1); a = (a + (cc & 0xffff)); b = ((int)minuendArr[minuendArrStart + i] & 0xffff) - (a & 0xffff); resultArr[resultStart + i] = ((short)b); cc = ((a >> 16) & 0xffff) + ((b >> 31) & 1); } a = cc & 0xffff; b = ((int)minuendArr[minuendArrStart + factor2Count] & 0xffff) - a; resultArr[resultStart + factor2Count] = ((short)b); cc = (b >> 31) & 1; return (short)cc; } private static void DivideThreeBlocksByTwo( short[] valueALow, int posALow, short[] valueAMidHigh, int posAMidHigh, short[] b, int posB, int blockCount, short[] quot, int posQuot, short[] rem, int posRem, short[] tmp) { // NOTE: size of 'quot' equals 'blockCount' * 2 // NOTE: size of 'rem' equals 'blockCount' * 2 // Implements Algorithm 2 of Burnikel & Ziegler 1998 int c; // If AHigh is less than BHigh if ( WordsCompare( valueAMidHigh, posAMidHigh + blockCount, blockCount, b, posB + blockCount, blockCount) < 0) { // Divide AMidHigh by BHigh RecursiveDivideInner( valueAMidHigh, posAMidHigh, b, posB + blockCount, quot, posQuot, rem, posRem, blockCount); // Copy remainder to temp at block position 4 System.arraycopy(rem, posRem, tmp, blockCount * 4, blockCount); java.util.Arrays.fill(tmp, blockCount * 5, (blockCount * 5)+(blockCount), (short)0); } else { // BHigh is less than AHigh // set quotient to all ones for (int i = 0; i < blockCount; ++i) { quot[posQuot + i] = ((short)0xffff); } java.util.Arrays.fill(quot, posQuot + blockCount, (posQuot + blockCount)+(blockCount), (short)0); // copy AMidHigh to temp System.arraycopy( valueAMidHigh, posAMidHigh, tmp, blockCount * 4, blockCount * 2); // subtract BHigh from temp's high block SubtractInternal( tmp, blockCount * 5, tmp, blockCount * 5, b, posB + blockCount, blockCount); // add BHigh to temp c = AddInternal( tmp, blockCount * 4, tmp, blockCount * 4, b, posB + blockCount, blockCount); Increment(tmp, blockCount * 5, blockCount, (short)c); } AsymmetricMultiply( tmp, 0, tmp, blockCount * 2, quot, posQuot, blockCount, b, posB, blockCount); int bc3 = blockCount * 3; System.arraycopy(valueALow, posALow, tmp, bc3, blockCount); java.util.Arrays.fill(tmp, blockCount * 2, (blockCount * 2)+(blockCount), (short)0); c = SubtractInternal(tmp, bc3, tmp, bc3, tmp, 0, blockCount * 3); if (c != 0) { while (true) { c = AddInternal(tmp, bc3, tmp, bc3, b, posB, blockCount * 2); c = Increment(tmp, blockCount * 5, blockCount, (short)c); Decrement(quot, posQuot, blockCount * 2, (short)1); if (c != 0) { break; } } } System.arraycopy(tmp, bc3, rem, posRem, blockCount * 2); } private static void RecursiveDivideInner( short[] a, int posA, short[] b, int posB, short[] quot, int posQuot, short[] rem, int posRem, int blockSize) { // NOTE: size of 'a', 'quot', and 'rem' is 'blockSize'*2 // NOTE: size of 'b' is 'blockSize' // Implements Algorithm 1 of Burnikel & Ziegler 1998 if (blockSize < RecursiveDivisionLimit || (blockSize & 1) == 1) { GeneralDivide( a, posA, blockSize * 2, b, posB, blockSize, quot, posQuot, rem, posRem); } else { int halfBlock = blockSize >> 1; short[] tmp = new short[halfBlock * 10]; java.util.Arrays.fill(quot, posQuot, (posQuot)+(blockSize * 2), (short)0); java.util.Arrays.fill(rem, posRem, (posRem)+(blockSize), (short)0); DivideThreeBlocksByTwo( a, posA + halfBlock, a, posA + blockSize, b, posB, halfBlock, tmp, halfBlock * 6, tmp, halfBlock * 8, tmp); DivideThreeBlocksByTwo( a, posA, tmp, halfBlock * 8, b, posB, halfBlock, quot, posQuot, rem, posRem, tmp); System.arraycopy(tmp, halfBlock * 6, quot, posQuot + halfBlock, halfBlock); } } private static void RecursiveDivide( short[] a, int posA, int countA, short[] b, int posB, int countB, short[] quot, int posQuot, short[] rem, int posRem) { int workPosA, workPosB, i; short[] workA = a; short[] workB = b; workPosA = posA; workPosB = posB; int blocksB = RecursiveDivisionLimit; int shiftB = 0; int m = 1; while (blocksB < countB) { blocksB <<= 1; m <<= 1; } workB = new short[blocksB]; workPosB = 0; System.arraycopy(b, posB, workB, blocksB - countB, countB); int shiftA = 0; int extraWord = 0; int wordsA = countA + (blocksB - countB); if ((b[countB - 1] & 0x8000) == 0) { int x = b[countB - 1]; while ((x & 0x8000) == 0) { ++shiftB; x <<= 1; } x = a[countA - 1]; while ((x & 0x8000) == 0) { ++shiftA; x <<= 1; } if (shiftA < shiftB) { // Shifting A would require an extra word ++extraWord; } ShiftWordsLeftByBits( workB, workPosB + blocksB - countB, countB, shiftB); } int blocksA = (wordsA + extraWord + (blocksB - 1)) / blocksB; int totalWordsA = blocksA * blocksB; workA = new short[totalWordsA]; workPosA = 0; System.arraycopy( a, posA, workA, workPosA + (blocksB - countB), countA); ShiftWordsLeftByBits( workA, workPosA + (blocksB - countB), countA + extraWord, shiftB); // Start division // "tmprem" holds temporary space for the following: // - blocksB: Remainder // - blocksB * 2: Dividend // - blocksB * 2: Quotient short[] tmprem = new short[blocksB * 5]; int size = 0; for (i = blocksA - 1; i >= 0; --i) { int workAIndex = workPosA + (i * blocksB); // Set the low part of the sub-dividend with the working // block of the dividend System.arraycopy(workA, workAIndex, tmprem, blocksB, blocksB); // Clear the quotient java.util.Arrays.fill(tmprem, blocksB * 3, (blocksB * 3)+(blocksB << 1), (short)0); RecursiveDivideInner( tmprem, blocksB, workB, workPosB, tmprem, blocksB * 3, tmprem, 0, blocksB); if (quot != null) { size = Math.min(blocksB, quot.length - (i * blocksB)); // DebugUtility.Log("quot len=" + quot.length + ",bb=" + blocksB + // ",size=" + size + " [" + countA + "," + countB + "]"); if (size > 0) { System.arraycopy( tmprem, blocksB * 3, quot, posQuot + (i * blocksB), size); } } // Set the high part of the sub-dividend with the remainder System.arraycopy(tmprem, 0, tmprem, blocksB << 1, blocksB); } if (rem != null) { System.arraycopy(tmprem, blocksB - countB, rem, posRem, countB); ShiftWordsRightByBits(rem, posRem, countB, shiftB); } } private static String WordsToString(short[] a, int pos, int len) { while (len != 0 && a[pos + len - 1] == 0) { --len; } if (len == 0) { return "\"0\""; } short[] words = new short[len]; System.arraycopy(a, pos, words, 0, len); return "\"" + new EInteger(len, words, false).ToUnoptString() + "\""; } private static String WordsToStringHex(short[] a, int pos, int len) { while (len != 0 && a[pos + len - 1] == 0) { --len; } if (len == 0) { return "\"0\""; } short[] words = new short[len]; System.arraycopy(a, pos, words, 0, len); return "\"" + new EInteger(len, words, false).ToRadixString(16) + "\""; } private static String WordsToString2( short[] a, int pos, int len, short[] b, int pos2, int len2) { short[] words = new short[len + len2]; System.arraycopy(a, pos, words, 0, len); System.arraycopy(b, pos2, words, len, len2); len += len2; while (len != 0 && words[len - 1] == 0) { --len; } return (len == 0) ? "\"0\"" : ("\"" + new EInteger( len, words, false).ToUnoptString() + "\""); } private static short[] CombineWords( short[] a, int pos, int len, short[] b, int pos2, int len2) { short[] words = new short[len + len2]; System.arraycopy(a, pos, words, 0, len); System.arraycopy(b, pos2, words, len, len2); return words; } private static void GeneralDivide( short[] a, int posA, int countA, short[] b, int posB, int countB, short[] quot, int posQuot, short[] rem, int posRem) { int origQuotSize = countA - countB + 1; int origCountA = countA; int origCountB = countB; while (countB > 0 && b[posB + countB - 1] == 0) { --countB; } while (countA > 0 && a[posA + countA - 1] == 0) { --countA; } int newQuotSize = countA - countB + 1; if (quot != null) { if (newQuotSize < 0 || newQuotSize >= origQuotSize) { java.util.Arrays.fill(quot, posQuot, (posQuot)+(Math.max(0, origQuotSize)), (short)0); } else { java.util.Arrays.fill(quot, posQuot + newQuotSize, (posQuot + newQuotSize)+(Math.max(0, origQuotSize - newQuotSize)), (short)0); } } if (rem != null) { java.util.Arrays.fill(rem, posRem + countB, (posRem + countB)+(origCountB - countB), (short)0); } if (countA < countB) { // A is less than B, so quotient is 0, remainder is "a" if (quot != null) { java.util.Arrays.fill(quot, posQuot, (posQuot)+(Math.max(0, origQuotSize)), (short)0); } if (rem != null) { System.arraycopy(a, posA, rem, posRem, origCountA); } return; } else if (countA == countB) { int cmp = Compare(a, posA, b, posB, countA); if (cmp == 0) { // A equals B, so quotient is 1, remainder is 0 if (quot != null) { quot[posQuot] = 1; java.util.Arrays.fill(quot, posQuot + 1, (posQuot + 1)+(Math.max(0, origQuotSize - 1)), (short)0); } if (rem != null) { java.util.Arrays.fill(rem, posRem, (posRem)+(countA), (short)0); } return; } else if (cmp < 0) { // A is less than B, so quotient is 0, remainder is "a" if (quot != null) { java.util.Arrays.fill(quot, posQuot, (posQuot)+(Math.max(0, origQuotSize)), (short)0); } if (rem != null) { System.arraycopy(a, posA, rem, posRem, origCountA); } return; } } if (countB == 1) { // Divisor is a single word short shortRemainder = FastDivideAndRemainder( quot, posQuot, a, posA, countA, b[posB]); if (rem != null) { rem[posRem] = shortRemainder; } return; } int workPosA, workPosB; short[] workAB = null; short[] workA = a; short[] workB = b; workPosA = posA; workPosB = posB; if (countB > RecursiveDivisionLimit) { RecursiveDivide( a, posA, countA, b, posB, countB, quot, posQuot, rem, posRem); return; } int sh = 0; boolean noShift = false; if ((b[posB + countB - 1] & 0x8000) == 0) { // Normalize a and b by shifting both until the high // bit of b is the highest bit of the last word int x = b[posB + countB - 1]; if (x == 0) { throw new IllegalStateException(); } while ((x & 0x8000) == 0) { ++sh; x <<= 1; } workAB = new short[countA + 1 + countB]; workPosA = 0; workPosB = countA + 1; workA = workAB; workB = workAB; System.arraycopy(a, posA, workA, workPosA, countA); System.arraycopy(b, posB, workB, workPosB, countB); ShiftWordsLeftByBits(workA, workPosA, countA + 1, sh); ShiftWordsLeftByBits(workB, workPosB, countB, sh); } else { noShift = true; workA = new short[countA + 1]; workPosA = 0; System.arraycopy(a, posA, workA, workPosA, countA); } int c = 0; short pieceBHigh = workB[workPosB + countB - 1]; int pieceBHighInt = ((int)pieceBHigh) & 0xffff; int endIndex = workPosA + countA; short pieceBNextHigh = workB[workPosB + countB - 2]; int pieceBNextHighInt = ((int)pieceBNextHigh) & 0xffff; for (int offset = countA - countB; offset >= 0; --offset) { int wpoffset = workPosA + offset; int wpaNextHigh = ((int)workA[wpoffset + countB - 1]) & 0xffff; int wpaHigh = 0; if (!noShift || wpoffset + countB < endIndex) { wpaHigh = ((int)workA[wpoffset + countB]) & 0xffff; } int dividend = (wpaNextHigh + (wpaHigh << 16)); int divnext = ((int)workA[wpoffset + countB - 2]) & 0xffff; int quorem0 = (dividend >> 31) == 0 ? (dividend / pieceBHighInt) : ((int)(((long)dividend & 0xffffffffL) / pieceBHighInt)); int quorem1 = (dividend - (quorem0 * pieceBHighInt)); // DebugUtility.Log("{0:X8}/{1:X4} = {2:X8},{3:X4}", // dividend, pieceBHigh, quorem0, quorem1); long t = (((long)quorem1) << 16) | (divnext & 0xffffL); // NOTE: quorem0 won't be higher than (1<< 16)+1 as long as // pieceBHighInt is // normalized (see Burnikel & Ziegler 1998). Since the following // code block // corrects all cases where quorem0 is too high by 2, and all // remaining cases // will reduce quorem0 by 1 if it's at least (1<< 16), quorem0 will // be guaranteed to // have a bit length of 16 or less by the end of the code block. if ((quorem0 >> 16) != 0 || ((quorem0 * pieceBNextHighInt) & 0xffffffffL) > t) { quorem1 += pieceBHighInt; --quorem0; if ((quorem1 >> 16) == 0) { t = (((long)quorem1) << 16) | (divnext & 0xffffL); if ((quorem0 >> 16) != 0 || ((quorem0 * pieceBNextHighInt) & 0xffffffffL) > t) { --quorem0; if (rem == null && offset == 0) { // We can stop now and break; all cases where quorem0 // is 2 too big will have been caught by now if (quot != null) { quot[posQuot + offset] = ((short)quorem0); } break; } } } } int q1 = quorem0 & 0xffff; c = LinearMultiplySubtractMinuend1Bigger( workA, wpoffset, workA, wpoffset, q1, workB, workPosB, countB); if (c != 0) { // T(workA,workPosA,countA+1,"workA X"); c = AddInternal( workA, wpoffset, workA, wpoffset, workB, workPosB, countB); c = Increment(workA, wpoffset + countB, 1, (short)c); // T(workA,workPosA,countA+1,"workA "+c); --quorem0; } if (quot != null) { quot[posQuot + offset] = ((short)quorem0); } } if (rem != null) { if (sh != 0) { ShiftWordsRightByBits(workA, workPosA, countB + 1, sh); } System.arraycopy(workA, workPosA, rem, posRem, countB); } } /** * Divides this object by another arbitrary-precision integer and returns the * quotient and remainder. * @param divisor The number to divide by. * @return An array with two arbitrary-precision integers: the first is the * quotient, and the second is the remainder. * @throws ArithmeticException The parameter divisor is 0. * @throws java.lang.NullPointerException The parameter {@code divisor} is null. */ public EInteger[] DivRem(EInteger divisor) { if (divisor == null) { throw new NullPointerException("divisor"); } int words1Size = this.wordCount; int words2Size = divisor.wordCount; if (words2Size == 0) { throw new ArithmeticException(); } if (words1Size < words2Size) { // dividend is less than divisor (includes case // where dividend is 0) return new EInteger[] { EInteger.FromInt32(0), this }; } if (words2Size == 1) { // divisor is small, use a fast path short[] quotient = new short[this.wordCount]; int smallRemainder; switch (divisor.words[0]) { case 2: smallRemainder = (int)FastDivideAndRemainderTwo( quotient, 0, this.words, 0, words1Size); break; case 10: smallRemainder = (int)FastDivideAndRemainderTen( quotient, 0, this.words, 0, words1Size); break; default: // DebugUtility.Log("smalldiv=" + (divisor.words[0])); smallRemainder = ((int)FastDivideAndRemainder( quotient, 0, this.words, 0, words1Size, divisor.words[0])) & 0xffff; break; } int count = this.wordCount; while (count != 0 && quotient[count - 1] == 0) { --count; } if (count == 0) { return new EInteger[] { EInteger.FromInt32(0), this }; } quotient = ShortenArray(quotient, count); EInteger bigquo = new EInteger( count, quotient, this.negative ^ divisor.negative); if (this.negative) { smallRemainder = -smallRemainder; } return new EInteger[] { bigquo, EInteger.FromInt64(smallRemainder) }; } if (this.CanFitInInt32() && divisor.CanFitInInt32()) { long dividendSmall = this.ToInt32Checked(); long divisorSmall = divisor.ToInt32Checked(); if (dividendSmall != Integer.MIN_VALUE || divisorSmall != -1) { long quotientSmall = dividendSmall / divisorSmall; long remainderSmall = dividendSmall - (quotientSmall * divisorSmall); return new EInteger[] { EInteger.FromInt64(quotientSmall), EInteger.FromInt64(remainderSmall) }; } } else if (this.CanFitInInt64() && divisor.CanFitInInt64()) { long dividendLong = this.ToInt64Checked(); long divisorLong = divisor.ToInt64Checked(); if (dividendLong != Long.MIN_VALUE || divisorLong != -1) { long quotientLong = dividendLong / divisorLong; long remainderLong = dividendLong - (quotientLong * divisorLong); return new EInteger[] { EInteger.FromInt64(quotientLong), EInteger.FromInt64(remainderLong) }; } // DebugUtility.Log("int64divrem {0}/{1}" // , this.ToInt64Checked(), divisor.ToInt64Checked()); } // --- General case short[] bigRemainderreg = new short[((int)words2Size)]; short[] quotientreg = new short[((int)(words1Size - words2Size + 1))]; GeneralDivide( this.words, 0, this.wordCount, divisor.words, 0, divisor.wordCount, quotientreg, 0, bigRemainderreg, 0); int remCount = CountWords(bigRemainderreg); int quoCount = CountWords(quotientreg); bigRemainderreg = ShortenArray(bigRemainderreg, remCount); quotientreg = ShortenArray(quotientreg, quoCount); EInteger bigrem = (remCount == 0) ? EInteger.FromInt32(0) : new EInteger(remCount, bigRemainderreg, this.negative); EInteger bigquo2 = (quoCount == 0) ? EInteger.FromInt32(0) : new EInteger(quoCount, quotientreg, this.negative ^ divisor.negative); return new EInteger[] { bigquo2, bigrem }; } /** * Determines whether this object and another object are equal and have the * same type. * @param obj The parameter {@code obj} is an arbitrary object. * @return {@code true} if this object and another object are equal; otherwise, * {@code false} . */ @Override public boolean equals(Object obj) { EInteger other = ((obj instanceof EInteger) ? (EInteger)obj : null); if (other == null) { return false; } if (this.wordCount == other.wordCount) { if (this.negative != other.negative) { return false; } for (int i = 0; i < this.wordCount; ++i) { if (this.words[i] != other.words[i]) { return false; } } return true; } return false; } private static EInteger LeftShiftBigIntVar(EInteger ei, EInteger bigShift) { if (ei.isZero()) { return ei; } while (bigShift.signum() > 0) { int shift = 1000000; if (bigShift.compareTo(EInteger.FromInt64(1000000)) < 0) { shift = bigShift.ToInt32Checked(); } ei = ei.ShiftLeft(shift); bigShift = bigShift.Subtract(EInteger.FromInt32(shift)); } return ei; } private static EInteger GcdLong(long u, long v) { // Adapted from Christian Stigen Larsen's // public domain GCD code int shl = 0; while (u != 0 && v != 0 && u != v) { boolean eu = (u & 1L) == 0; boolean ev = (v & 1L) == 0; if (eu && ev) { ++shl; u >>= 1; v >>= 1; } else if (eu && !ev) { u >>= 1; } else if (!eu && ev) { v >>= 1; } else if (u >= v) { u = (u - v) >> 1; } else { long tmp = u; u = (v - u) >> 1; v = tmp; } } EInteger eret = (u == 0) ? EInteger.FromInt64(v << shl) : EInteger.FromInt64(u << shl); return eret; } /** * Returns the greatest common divisor of this integer and the given integer. * The greatest common divisor (GCD) is also known as the greatest * common factor (GCF). * @param bigintSecond Another arbitrary-precision integer. * @return An arbitrary-precision integer. * @throws java.lang.NullPointerException The parameter {@code bigintSecond} is * null. */ public EInteger Gcd(EInteger bigintSecond) { if (bigintSecond == null) { throw new NullPointerException("bigintSecond"); } if (this.isZero()) { return bigintSecond.Abs(); } EInteger thisValue = this.Abs(); if (bigintSecond.isZero()) { return thisValue; } bigintSecond = bigintSecond.Abs(); if (bigintSecond.equals(EInteger.FromInt32(1)) || thisValue.equals(bigintSecond)) { return bigintSecond; } if (thisValue.equals(EInteger.FromInt32(1))) { return thisValue; } if (thisValue.CanFitInInt64() && bigintSecond.CanFitInInt64()) { long u = thisValue.ToInt64Unchecked(); long v = bigintSecond.ToInt64Unchecked(); return GcdLong(u, v); } else { // Big integer version of code above int bshl = 0; EInteger ebshl = null; short[] bu = thisValue.Copy(); short[] bv = bigintSecond.Copy(); int buc = thisValue.wordCount; int bvc = bigintSecond.wordCount; while (buc != 0 && bvc != 0 && !WordsEqual(bu, buc, bv, bvc)) { if (buc <= 3 && bvc <= 3) { return GcdLong( WordsToLongUnchecked(bu, buc), WordsToLongUnchecked(bv, bvc)); } if ((bu[0] & 0x0f) == 0 && (bv[0] & 0x0f) == 0) { if (bshl < 0) { ebshl = ebshl.Add(EInteger.FromInt32(4)); } else if (bshl == Integer.MAX_VALUE - 3) { ebshl = EInteger.FromInt32(Integer.MAX_VALUE - 3); ebshl = ebshl.Add(EInteger.FromInt32(4)); bshl = -1; } else { bshl += 4; } buc = WordsShiftRightFour(bu, buc); bvc = WordsShiftRightFour(bv, bvc); continue; } boolean eu = (bu[0] & 0x01) == 0; boolean ev = (bv[0] & 0x01) == 0; if (eu && ev) { if (bshl < 0) { ebshl = ebshl.Add(EInteger.FromInt32(1)); } else if (bshl == Integer.MAX_VALUE) { ebshl = EInteger.FromInt32(Integer.MAX_VALUE); ebshl = ebshl.Add(EInteger.FromInt32(1)); bshl = -1; } else { ++bshl; } buc = WordsShiftRightOne(bu, buc); bvc = WordsShiftRightOne(bv, bvc); } else if (eu && !ev) { buc = (Math.abs(buc - bvc) > 1 && (bu[0] & 0x0f) == 0) ? WordsShiftRightFour(bu, buc) : WordsShiftRightOne(bu, buc); } else if (!eu && ev) { if ((bv[0] & 0xff) == 0 && Math.abs(buc - bvc) > 1) { // DebugUtility.Log("bv8"); bvc = WordsShiftRightEight(bv, bvc); } else { bvc = ( (bv[0] & 0x0f) == 0 && Math.abs( buc - bvc) > 1) ? WordsShiftRightFour(bv, bvc) : WordsShiftRightOne(bv, bvc); } } else if (WordsCompare(bu, buc, bv, bvc) >= 0) { buc = WordsSubtract(bu, buc, bv, bvc); buc = (Math.abs(buc - bvc) > 1 && (bu[0] & 0x02) == 0) ? WordsShiftRightTwo(bu, buc) : WordsShiftRightOne(bu, buc); } else { short[] butmp = bv; short[] bvtmp = bu; int buctmp = bvc; int bvctmp = buc; buctmp = WordsSubtract(butmp, buctmp, bvtmp, bvctmp); buctmp = WordsShiftRightOne(butmp, buctmp); bu = butmp; bv = bvtmp; buc = buctmp; bvc = bvctmp; } } EInteger valueBuVar = new EInteger(buc, bu, false); EInteger valueBvVar = new EInteger(bvc, bv, false); if (bshl >= 0) { valueBuVar = valueBuVar.isZero() ? (valueBvVar.ShiftLeft(bshl)) : (valueBuVar.ShiftLeft(bshl)); } else { valueBuVar = valueBuVar.isZero() ? LeftShiftBigIntVar( valueBvVar, ebshl) : LeftShiftBigIntVar( valueBuVar, ebshl); } return valueBuVar; } } /** * Returns the number of decimal digits used by this integer. * @return The number of digits in the decimal form of this integer. Returns 1 * if this number is 0. */ public int GetDigitCount() { if (this.isZero()) { return 1; } if (this.HasSmallValue()) { long value = this.ToInt64Checked(); if (value == Long.MIN_VALUE) { return 19; } if (value < 0) { value = -value; } if (value >= 1000000000L) { return (value >= 1000000000000000000L) ? 19 : ((value >= 100000000000000000L) ? 18 : ((value >= 10000000000000000L) ? 17 : ((value >= 1000000000000000L) ? 16 : ((value >= 100000000000000L) ? 15 : ((value >= 10000000000000L) ? 14 : ((value >= 1000000000000L) ? 13 : ((value >= 100000000000L) ? 12 : ((value >= 10000000000L) ? 11 : ((value >= 1000000000L) ? 10 : 9))))))))); } else { int v2 = (int)value; return (v2 >= 100000000) ? 9 : ((v2 >= 10000000) ? 8 : ((v2 >= 1000000) ? 7 : ((v2 >= 100000) ? 6 : ((v2 >= 10000) ? 5 : ((v2 >= 1000) ? 4 : ((v2 >= 100) ? 3 : ((v2 >= 10) ? 2 : 1))))))); } } int bitlen = this.GetUnsignedBitLength(); if (bitlen <= 2135) { // (x*631305) >> 21 is an approximation // to trunc(x*log10(2)) that is correct up // to x = 2135; the multiplication would require // up to 31 bits in all cases up to 2135 // (cases up to 63 are already handled above) int minDigits = 1 + (((bitlen - 1) * 631305) >> 21); int maxDigits = 1 + ((bitlen * 631305) >> 21); if (minDigits == maxDigits) { // Number of digits is the same for // all numbers with this bit length return minDigits; } return this.Abs().compareTo(NumberUtility.FindPowerOfTen(minDigits)) >= 0 ? maxDigits : minDigits; } else if (bitlen <= 6432162) { // Much more accurate approximation int minDigits = ApproxLogTenOfTwo(bitlen - 1); int maxDigits = ApproxLogTenOfTwo(bitlen); if (minDigits == maxDigits) { // Number of digits is the same for // all numbers with this bit length return 1 + minDigits; } if (bitlen < 50000) { return this.Abs().compareTo(NumberUtility.FindPowerOfTen(minDigits + 1)) >= 0 ? maxDigits + 1 : minDigits + 1; } } short[] tempReg = null; int currentCount = this.wordCount; int i = 0; while (currentCount != 0) { if (currentCount == 1 || (currentCount == 2 && tempReg[1] == 0)) { int rest = ((int)tempReg[0]) & 0xffff; if (rest >= 10000) { i += 5; } else if (rest >= 1000) { i += 4; } else if (rest >= 100) { i += 3; } else if (rest >= 10) { i += 2; } else { ++i; } break; } if (currentCount == 2 && tempReg[1] > 0 && tempReg[1] <= 0x7fff) { int rest = ((int)tempReg[0]) & 0xffff; rest |= (((int)tempReg[1]) & 0xffff) << 16; if (rest >= 1000000000) { i += 10; } else if (rest >= 100000000) { i += 9; } else if (rest >= 10000000) { i += 8; } else if (rest >= 1000000) { i += 7; } else if (rest >= 100000) { i += 6; } else if (rest >= 10000) { i += 5; } else if (rest >= 1000) { i += 4; } else if (rest >= 100) { i += 3; } else if (rest >= 10) { i += 2; } else { ++i; } break; } else { int wci = currentCount; short remainderShort = 0; int quo, rem; boolean firstdigit = false; short[] dividend = (tempReg == null) ? (this.words) : tempReg; // Divide by 10000 while ((wci--) > 0) { int curValue = ((int)dividend[wci]) & 0xffff; int currentDividend = ((int)(curValue | ((int)remainderShort << 16))); quo = currentDividend / 10000; if (!firstdigit && quo != 0) { firstdigit = true; // Since we are dividing from left to right, the first // nonzero result is the first part of the // new quotient bitlen = GetUnsignedBitLengthEx(quo, wci + 1); if (bitlen <= 2135) { // (x*631305) >> 21 is an approximation // to trunc(x*log10(2)) that is correct up // to x = 2135; the multiplication would require // up to 31 bits in all cases up to 2135 // (cases up to 64 are already handled above) int minDigits = 1 + (((bitlen - 1) * 631305) >> 21); int maxDigits = 1 + ((bitlen * 631305) >> 21); if (minDigits == maxDigits) { // Number of digits is the same for // all numbers with this bit length // NOTE: The 4 is the number of digits just // taken out of the number, and "i" is the // number of previously known digits return i + minDigits + 4; } if (minDigits > 1) { int maxDigitEstimate = i + maxDigits + 4; int minDigitEstimate = i + minDigits + 4; return this.Abs().compareTo(NumberUtility.FindPowerOfTen(minDigitEstimate)) >= 0 ? maxDigitEstimate : minDigitEstimate; } } else if (bitlen <= 6432162) { // Much more accurate approximation int minDigits = ApproxLogTenOfTwo(bitlen - 1); int maxDigits = ApproxLogTenOfTwo(bitlen); if (minDigits == maxDigits) { // Number of digits is the same for // all numbers with this bit length return i + 1 + minDigits + 4; } } } if (tempReg == null) { if (quo != 0) { tempReg = new short[this.wordCount]; System.arraycopy(this.words, 0, tempReg, 0, tempReg.length); // Use the calculated word count during division; // zeros that may have occurred in division // are not incorporated in the tempReg currentCount = wci + 1; tempReg[wci] = ((short)quo); } } else { tempReg[wci] = ((short)quo); } rem = currentDividend - (10000 * quo); remainderShort = ((short)rem); } // Recalculate word count while (currentCount != 0 && tempReg[currentCount - 1] == 0) { --currentCount; } i += 4; } } return i; } /** * Returns the hash code for this instance. No application or process IDs are * used in the hash code calculation. * @return A 32-bit signed integer. */ @Override public int hashCode() { int hashCodeValue = 0; { hashCodeValue += 1000000007 * this.signum(); if (this.words != null) { for (int i = 0; i < this.wordCount; ++i) { hashCodeValue += 1000000013 * this.words[i]; } } } return hashCodeValue; } /** * Gets the lowest set bit in this number's absolute value. (This will also be * the lowest set bit in the number's two's-complement form (see {@link * com.upokecenter.numbers.EDecimal "Forms of numbers" }).). * @return The lowest bit set in the number, starting at 0. Returns -1 if this * value is 0 or odd. */ public int GetLowBit() { int retSetBit = 0; for (int i = 0; i < this.wordCount; ++i) { int c = ((int)this.words[i]) & 0xffff; if (c == 0) { retSetBit += 16; } else { return (((c << 15) & 0xffff) != 0) ? (retSetBit + 0) : ((((c << 14) & 0xffff) != 0) ? (retSetBit + 1) : ((((c << 13) & 0xffff) != 0) ? (retSetBit + 2) : ((((c << 12) & 0xffff) != 0) ? (retSetBit + 3) : ((((c << 11) & 0xffff) != 0) ? (retSetBit + 4) : ((((c << 10) & 0xffff) != 0) ? (retSetBit + 5) : ((((c << 9) & 0xffff) != 0) ? (retSetBit + 6) : ((((c << 8) & 0xffff) != 0) ? (retSetBit + 7) : ((((c << 7) & 0xffff) != 0) ? (retSetBit + 8) : ((((c << 6) & 0xffff) != 0) ? (retSetBit + 9) : ((((c << 5) & 0xffff) != 0) ? (retSetBit + 10) : ((((c << 4) & 0xffff) != 0) ? (retSetBit + 11) : ((((c << 3) & 0xffff) != 0) ? (retSetBit + 12) : ((((c << 2) & 0xffff) != 0) ? (retSetBit + 13) : ((((c << 1) & 0xffff) != 0) ? (retSetBit + 14) : (retSetBit + 15))))))))))))))); } } return -1; } /** * Gets the lowest set bit in this number's absolute value. (This will also be * the lowest set bit in the number's two's-complement form (see {@link * com.upokecenter.numbers.EDecimal "Forms of numbers" }).). * @return The lowest bit set in the number, starting at 0. Returns -1 if this * value is 0 or odd. */ public EInteger GetLowBitAsEInteger() { long retSetBitLong = 0; for (int i = 0; i < this.wordCount; ++i) { int c = ((int)this.words[i]) & 0xffff; if (c == 0) { retSetBitLong += 16; } else { int rsb = (((c << 15) & 0xffff) != 0) ? 0 : ((((c << 14) & 0xffff) != 0) ? 1 : ((((c << 13) & 0xffff) != 0) ? 2 : ((((c << 12) & 0xffff) != 0) ? 3 : ((((c << 11) & 0xffff) != 0) ? 4 : ((((c << 10) & 0xffff) != 0) ? 5 : ((((c << 9) & 0xffff) != 0) ? 6 : ((((c << 8) & 0xffff) != 0) ? 7 : ((((c << 7) & 0xffff) != 0) ? 8 : ((((c << 6) & 0xffff) != 0) ? 9 : ((((c << 5) & 0xffff) != 0) ? 10 : ((((c << 4) & 0xffff) != 0) ? 11 : ((((c << 3) & 0xffff) != 0) ? 12 : ((((c << 2) & 0xffff) != 0) ? 13 : ((((c << 1) & 0xffff) != 0) ? 14 : 15)))))))))))))); return EInteger.FromInt64(retSetBitLong).Add( EInteger.FromInt32(rsb)); } } return EInteger.FromInt32(-1); } /** * Returns whether a bit is set in the two's-complement form (see {@link * com.upokecenter.numbers.EDecimal "Forms of numbers" }) of this * object' s value. * @param index The parameter {@code index} is a 32-bit signed integer. * @return {@code true} if a bit is set in the two' s-complement form (see * {@link com.upokecenter.numbers.EDecimal}) of this object' s value; * otherwise, {@code false} . */ public boolean GetSignedBit(int index) { if (index < 0) { throw new java.lang.IllegalArgumentException("index"); } if (this.wordCount == 0) { return false; } if (this.negative) { int tcindex = 0; int wordpos = index / 16; if (wordpos >= this.words.length) { return true; } while (tcindex < wordpos && this.words[tcindex] == 0) { ++tcindex; } short tc; { tc = this.words[wordpos]; if (tcindex == wordpos) { --tc; } tc = (short)~tc; } return (boolean)(((tc >> (int)(index & 15)) & 1) != 0); } return this.GetUnsignedBit(index); } /** * Finds the minimum number of bits needed to represent this object's value, * except for its sign. If the value is negative, finds the number of * bits in the value equal to this object's absolute value minus 1. * @return The number of bits in this object's value. Returns 0 if this * object's value is 0 or negative 1. */ public int GetSignedBitLength() { int wc = this.wordCount; if (wc != 0) { if (this.negative) { return this.Abs().Subtract(EInteger.FromInt32(1)).GetSignedBitLength(); } int numberValue = ((int)this.words[wc - 1]) & 0xffff; wc = (wc - 1) << 4; if (numberValue == 0) { return wc; } wc += 16; { if ((numberValue >> 8) == 0) { numberValue <<= 8; wc -= 8; } if ((numberValue >> 12) == 0) { numberValue <<= 4; wc -= 4; } if ((numberValue >> 14) == 0) { numberValue <<= 2; wc -= 2; } return ((numberValue >> 15) == 0) ? wc - 1 : wc; } } return 0; } /** * Returns whether a bit is set in this number's absolute value. * @param index Zero based index of the bit to test. 0 means the least * significant bit. * @return {@code true} if a bit is set in this number's absolute value. */ public boolean GetUnsignedBit(int index) { if (index < 0) { throw new IllegalArgumentException("index (" + index + ") is less than 0"); } return ((index >> 4) < this.words.length) && ((boolean)(((this.words[(index >> 4)] >> (int)(index & 15)) & 1) != 0)); } /** * Finds the minimum number of bits needed to represent this number's absolute * value. * @return The number of bits in this object's value. Returns 0 if this * object's value is 0, and returns 1 if the value is negative 1. */ public EInteger GetUnsignedBitLengthAsEInteger() { int wc = this.wordCount; if (wc != 0) { int numberValue = ((int)this.words[wc - 1]) & 0xffff; EInteger ebase = EInteger.FromInt32(wc - 1).ShiftLeft(4); if (numberValue == 0) { return ebase; } wc = 16; { if ((numberValue >> 8) == 0) { numberValue <<= 8; wc -= 8; } if ((numberValue >> 12) == 0) { numberValue <<= 4; wc -= 4; } if ((numberValue >> 14) == 0) { numberValue <<= 2; wc -= 2; } if ((numberValue >> 15) == 0) { --wc; } } return ebase.Add(EInteger.FromInt32(wc)); } return EInteger.FromInt32(0); } /** * Finds the minimum number of bits needed to represent this number's absolute * value. * @return The number of bits in this object's value. Returns 0 if this * object's value is 0, and returns 1 if the value is negative 1. */ public int GetUnsignedBitLength() { int wc = this.wordCount; if (wc != 0) { int numberValue = ((int)this.words[wc - 1]) & 0xffff; wc = (wc - 1) << 4; if (numberValue == 0) { return wc; } wc += 16; { if ((numberValue >> 8) == 0) { numberValue <<= 8; wc -= 8; } if ((numberValue >> 12) == 0) { numberValue <<= 4; wc -= 4; } if ((numberValue >> 14) == 0) { numberValue <<= 2; wc -= 2; } if ((numberValue >> 15) == 0) { --wc; } } return wc; } return 0; } /** * Finds the modulus remainder that results when this instance is divided by * the value of an arbitrary-precision integer. The modulus remainder is * the same as the normal remainder if the normal remainder is positive, * and equals divisor plus normal remainder if the normal remainder is * negative. * @param divisor The number to divide by. * @return An arbitrary-precision integer. * @throws java.lang.NullPointerException The parameter {@code divisor} is null. */ public EInteger Mod(EInteger divisor) { if (divisor == null) { throw new NullPointerException("divisor"); } if (divisor.signum() < 0) { throw new ArithmeticException("Divisor is negative"); } EInteger remainderEInt = this.Remainder(divisor); if (remainderEInt.signum() < 0) { remainderEInt = divisor.Add(remainderEInt); } return remainderEInt; } /** * Calculates the remainder when this arbitrary-precision integer raised to a * certain power is divided by another arbitrary-precision integer. * @param pow The power to raise this integer by. * @param mod The integer to divide the raised number by. * @return An arbitrary-precision integer. * @throws java.lang.NullPointerException The parameter {@code pow} or {@code * mod} is null. */ public EInteger ModPow(EInteger pow, EInteger mod) { if (pow == null) { throw new NullPointerException("pow"); } if (mod == null) { throw new NullPointerException("mod"); } if (pow.signum() < 0) { throw new IllegalArgumentException("pow (" + pow + ") is less than 0"); } if (mod.signum() <= 0) { throw new IllegalArgumentException("mod (" + mod + ") is not greater than 0"); } EInteger r = EInteger.FromInt32(1); EInteger eiv = this; while (!pow.isZero()) { if (!pow.isEven()) { r = (r.Multiply(eiv)).Mod(mod); } pow = pow.ShiftRight(1); if (!pow.isZero()) { eiv = (eiv.Multiply(eiv)).Mod(mod); } } return r; } /** * Multiplies this instance by the value of an arbitrary-precision integer * object. * @param bigintMult Another arbitrary-precision integer. * @return The product of the two numbers. * @throws java.lang.NullPointerException The parameter {@code bigintMult} is * null. */ public EInteger Multiply(EInteger bigintMult) { if (bigintMult == null) { throw new NullPointerException("bigintMult"); } if (this.wordCount == 0 || bigintMult.wordCount == 0) { return EInteger.FromInt32(0); } if (this.wordCount == 1 && this.words[0] == 1) { return this.negative ? bigintMult.Negate() : bigintMult; } if (bigintMult.wordCount == 1 && bigintMult.words[0] == 1) { return bigintMult.negative ? this.Negate() : this; } short[] productreg; int productwordCount; boolean needShorten = true; if (this.wordCount == 1) { int wc; if (bigintMult.wordCount == 1) { // NOTE: Result can't be 0 here, since checks // for 0 were already made earlier in this function productreg = new short[2]; int ba = ((int)this.words[0]) & 0xffff; int bb = ((int)bigintMult.words[0]) & 0xffff; ba = (ba * bb); productreg[0] = ((short)(ba & 0xffff)); productreg[1] = ((short)((ba >> 16) & 0xffff)); short preg = productreg[1]; wc = (preg == 0) ? 1 : 2; return new EInteger( wc, productreg, this.negative ^ bigintMult.negative); } wc = bigintMult.wordCount; int regLength = wc + 1; productreg = new short[regLength]; productreg[wc] = LinearMultiply( productreg, 0, bigintMult.words, 0, this.words[0], wc); productwordCount = productreg.length; needShorten = false; } else if (bigintMult.wordCount == 1) { int wc = this.wordCount; int regLength = wc + 1; productreg = new short[regLength]; productreg[wc] = LinearMultiply( productreg, 0, this.words, 0, bigintMult.words[0], wc); productwordCount = productreg.length; needShorten = false; } else if (this.equals(bigintMult)) { int words1Size = this.wordCount; productreg = new short[words1Size + words1Size]; productwordCount = productreg.length; short[] workspace = new short[words1Size + words1Size]; RecursiveSquare( productreg, 0, workspace, 0, this.words, 0, words1Size); } else if (this.wordCount <= 10 && bigintMult.wordCount <= 10) { int wc = this.wordCount + bigintMult.wordCount; productreg = new short[wc]; productwordCount = productreg.length; SchoolbookMultiply( productreg, 0, this.words, 0, this.wordCount, bigintMult.words, 0, bigintMult.wordCount); needShorten = false; } else { int words1Size = this.wordCount; int words2Size = bigintMult.wordCount; productreg = new short[(words1Size + words2Size)]; short[] workspace = new short[words1Size + words2Size]; productwordCount = productreg.length; AsymmetricMultiply( productreg, 0, workspace, 0, this.words, 0, words1Size, bigintMult.words, 0, words2Size); } // Recalculate word count while (productwordCount != 0 && productreg[productwordCount - 1] == 0) { --productwordCount; } if (needShorten) { productreg = ShortenArray(productreg, productwordCount); } return new EInteger( productwordCount, productreg, this.negative ^ bigintMult.negative); } /** * Gets the value of this object with the sign reversed. * @return This object's value with the sign reversed. */ public EInteger Negate() { return this.wordCount == 0 ? this : new EInteger( this.wordCount, this.words, !this.negative); } /** * Raises an arbitrary-precision integer to a power. * @param powerSmall The exponent to raise to. * @return The result. Returns 1 if "powerSmall" is 0. */ public EInteger Pow(int powerSmall) { if (powerSmall < 0) { throw new IllegalArgumentException("powerSmall (" + powerSmall + ") is less than 0"); } EInteger thisVar = this; if (powerSmall == 0) { // however 0 to the power of 0 is undefined return EInteger.FromInt32(1); } if (powerSmall == 1) { return this; } if (powerSmall == 2) { return thisVar.Multiply(thisVar); } if (powerSmall == 3) { return (thisVar.Multiply(thisVar)).Multiply(thisVar); } EInteger r = EInteger.FromInt32(1); while (powerSmall != 0) { if ((powerSmall & 1) != 0) { r = r.Multiply(thisVar); } powerSmall >>= 1; if (powerSmall != 0) { thisVar = thisVar.Multiply(thisVar); } } return r; } /** * Raises an arbitrary-precision integer to a power, which is given as another * arbitrary-precision integer. * @param power The exponent to raise to. * @return The result. Returns 1 if "power" is 0. * @throws IllegalArgumentException The parameter {@code power} is less than 0. * @throws java.lang.NullPointerException The parameter {@code power} is null. */ public EInteger PowBigIntVar(EInteger power) { if (power == null) { throw new NullPointerException("power"); } int sign = power.signum(); if (sign < 0) { throw new IllegalArgumentException( "sign (" + sign + ") is less than 0"); } EInteger thisVar = this; if (sign == 0) { return EInteger.FromInt32(1); } if (power.equals(EInteger.FromInt32(1))) { return this; } if (power.wordCount == 1 && power.words[0] == 2) { return thisVar.Multiply(thisVar); } if (power.wordCount == 1 && power.words[0] == 3) { return (thisVar.Multiply(thisVar)).Multiply(thisVar); } EInteger r = EInteger.FromInt32(1); while (!power.isZero()) { if (!power.isEven()) { r = r.Multiply(thisVar); } power = power.ShiftRight(1); if (!power.isZero()) { thisVar = thisVar.Multiply(thisVar); } } return r; } /** * Finds the remainder that results when this instance is divided by the value * of an arbitrary-precision integer. The remainder is the value that * remains when the absolute value of this object is divided by the * absolute value of the other object; the remainder has the same sign * (positive or negative) as this object. * @param divisor The number to divide by. * @return The remainder of the two numbers. * @throws ArithmeticException Attempted to divide by zero. * @throws java.lang.NullPointerException The parameter {@code divisor} is null. */ public EInteger Remainder(EInteger divisor) { if (divisor == null) { throw new NullPointerException("divisor"); } int words1Size = this.wordCount; int words2Size = divisor.wordCount; if (words2Size == 0) { throw new ArithmeticException(); } if (words1Size < words2Size) { // dividend is less than divisor return this; } if (words2Size == 1) { short shortRemainder = FastRemainder( this.words, this.wordCount, divisor.words[0]); int smallRemainder = ((int)shortRemainder) & 0xffff; if (this.negative) { smallRemainder = -smallRemainder; } return EInteger.FromInt64(smallRemainder); } if (this.PositiveCompare(divisor) < 0) { return this; } short[] remainderReg = new short[((int)words2Size)]; GeneralDivide( this.words, 0, this.wordCount, divisor.words, 0, divisor.wordCount, null, 0, remainderReg, 0); int count = CountWords(remainderReg); if (count == 0) { return EInteger.FromInt32(0); } remainderReg = ShortenArray(remainderReg, count); return new EInteger(count, remainderReg, this.negative); } /** * Returns an arbitrary-precision integer with the bits shifted to the left by * a number of bits. A value of 1 doubles this value, a value of 2 * multiplies it by 4, a value of 3 by 8, a value of 4 by 16, and so on. * @param numberBits The number of bits to shift. Can be negative, in which * case this is the same as shiftRight with the absolute value of this * parameter. * @return An arbitrary-precision integer. */ public EInteger ShiftLeft(int numberBits) { if (numberBits == 0 || this.wordCount == 0) { return this; } if (numberBits < 0) { return (numberBits == Integer.MIN_VALUE) ? this.ShiftRight(1).ShiftRight(Integer.MAX_VALUE) : this.ShiftRight(-numberBits); } int numWords = (int)this.wordCount; int shiftWords = (int)(numberBits >> 4); int shiftBits = (int)(numberBits & 15); if (!this.negative) { short[] ret = new short[(numWords + BitsToWords((int)numberBits))]; System.arraycopy(this.words, 0, ret, shiftWords, numWords); ShiftWordsLeftByBits( ret, (int)shiftWords, numWords + BitsToWords(shiftBits), shiftBits); return new EInteger(CountWords(ret), ret, false); } else { short[] ret = new short[(numWords + BitsToWords((int)numberBits))]; System.arraycopy(this.words, 0, ret, 0, numWords); TwosComplement(ret, 0, (int)ret.length); ShiftWordsLeftByWords(ret, 0, numWords + shiftWords, shiftWords); ShiftWordsLeftByBits( ret, (int)shiftWords, numWords + BitsToWords(shiftBits), shiftBits); TwosComplement(ret, 0, (int)ret.length); return new EInteger(CountWords(ret), ret, true); } } private short[] Copy() { short[] words = new short[this.words.length]; System.arraycopy(this.words, 0, words, 0, this.wordCount); return words; } private static int WordsCompare( short[] words, int wordCount, short[] words2, int wordCount2) { return WordsCompare(words, 0, wordCount, words2, 0, wordCount2); } private static int WordsCompare( short[] words, int pos1, int wordCount, short[] words2, int pos2, int wordCount2) { // NOTE: Assumes the number is nonnegative int size = wordCount; if (size == 0) { return (wordCount2 == 0) ? 0 : -1; } else if (wordCount2 == 0) { return 1; } if (size == wordCount2) { if (size == 1 && words[pos1] == words2[pos2]) { return 0; } else { int p1 = pos1 + size - 1; int p2 = pos2 + size - 1; while ((size--) != 0) { int an = ((int)words[p1]) & 0xffff; int bn = ((int)words2[p2]) & 0xffff; if (an > bn) { return 1; } if (an < bn) { return -1; } --p1; --p2; } return 0; } } return (size > wordCount2) ? 1 : -1; } private static long WordsToLongUnchecked(short[] words, int wordCount) { // NOTE: Assumes the number is nonnegative int c = (int)wordCount; if (c == 0) { return (long)0; } long ivv = 0; int intRetValue = ((int)words[0]) & 0xffff; if (c > 1) { intRetValue |= (((int)words[1]) & 0xffff) << 16; } if (c > 2) { int intRetValue2 = ((int)words[2]) & 0xffff; if (c > 3) { intRetValue2 |= (((int)words[3]) & 0xffff) << 16; } ivv = ((long)intRetValue) & 0xffffffffL; ivv |= ((long)intRetValue2) << 32; return ivv; } ivv = ((long)intRetValue) & 0xffffffffL; return ivv; } private static boolean WordsEqual( short[] words, int wordCount, short[] words2, int wordCount2) { // NOTE: Assumes the number is nonnegative if (wordCount == wordCount2) { for (int i = 0; i < wordCount; ++i) { if (words[i] != words2[i]) { return false; } } return true; } return false; } private static boolean WordsIsEven(short[] words, int wordCount) { return wordCount == 0 || (words[0] & 0x01) == 0; } private static int WordsShiftRightTwo(short[] words, int wordCount) { // NOTE: Assumes the number is nonnegative if (wordCount != 0) { int u; int carry = 0; for (int i = wordCount - 1; i >= 0; --i) { int w = words[i]; u = ((w & 0xfffc) >> 2) | carry; carry = (w << 14) & 0xc000; words[i] = ((short)u); } if (words[wordCount - 1] == 0) { --wordCount; } } return wordCount; } private static int WordsShiftRightEight(short[] words, int wordCount) { // NOTE: Assumes the number is nonnegative if (wordCount != 0) { int u; int carry = 0; for (int i = wordCount - 1; i >= 0; --i) { int w = words[i]; u = ((w & 0xff00) >> 8) | carry; carry = (w << 8) & 0xff00; words[i] = ((short)u); } if (words[wordCount - 1] == 0) { --wordCount; } } return wordCount; } private static int WordsShiftRightFour(short[] words, int wordCount) { // NOTE: Assumes the number is nonnegative if (wordCount != 0) { int u; int carry = 0; for (int i = wordCount - 1; i >= 0; --i) { int w = words[i]; u = ((w & 0xfff0) >> 4) | carry; carry = (w << 12) & 0xf000; words[i] = ((short)u); } if (words[wordCount - 1] == 0) { --wordCount; } } return wordCount; } private static int WordsShiftRightOne(short[] words, int wordCount) { // NOTE: Assumes the number is nonnegative if (wordCount != 0) { int u; int carry = 0; for (int i = wordCount - 1; i >= 0; --i) { int w = words[i]; u = ((w & 0xfffe) >> 1) | carry; carry = (w << 15) & 0x8000; words[i] = ((short)u); } if (words[wordCount - 1] == 0) { --wordCount; } } return wordCount; } private static int WordsSubtract( short[] words, int wordCount, short[] subtrahendWords, int subtrahendCount) { // NOTE: Assumes this value is at least as high as the subtrahend // and both numbers are nonnegative short borrow = (short)SubtractInternal( words, 0, words, 0, subtrahendWords, 0, subtrahendCount); if (borrow != 0) { Decrement( words, subtrahendCount, (int)(wordCount - subtrahendCount), borrow); } while (wordCount != 0 && words[wordCount - 1] == 0) { --wordCount; } return wordCount; } /** * Returns an arbitrary-precision integer with the bits shifted to the right. * For this operation, the arbitrary-precision integer is treated as a * two's-complement form (see {@link com.upokecenter.numbers.EDecimal * "Forms of numbers" }). Thus, for negative values, the * arbitrary-precision integer is sign-extended. * @param numberBits Number of bits to shift right. * @return An arbitrary-precision integer. */ public EInteger ShiftRight(int numberBits) { if (numberBits == 0 || this.wordCount == 0) { return this; } if (numberBits < 0) { return (numberBits == Integer.MIN_VALUE) ? this.ShiftLeft(1).ShiftLeft(Integer.MAX_VALUE) : this.ShiftLeft(-numberBits); } int numWords = (int)this.wordCount; int shiftWords = (int)(numberBits >> 4); int shiftBits = (int)(numberBits & 15); short[] ret; int retWordCount; if (this.negative) { ret = new short[this.words.length]; System.arraycopy(this.words, 0, ret, 0, numWords); TwosComplement(ret, 0, (int)ret.length); ShiftWordsRightByWordsSignExtend(ret, 0, numWords, shiftWords); if (numWords > shiftWords) { ShiftWordsRightByBitsSignExtend( ret, 0, numWords - shiftWords, shiftBits); } TwosComplement(ret, 0, (int)ret.length); retWordCount = ret.length; } else { if (shiftWords >= numWords) { return EInteger.FromInt32(0); } ret = new short[this.words.length]; System.arraycopy(this.words, shiftWords, ret, 0, numWords - shiftWords); if (shiftBits != 0) { ShiftWordsRightByBits(ret, 0, numWords - shiftWords, shiftBits); } retWordCount = numWords - shiftWords; } while (retWordCount != 0 && ret[retWordCount - 1] == 0) { --retWordCount; } if (retWordCount == 0) { return EInteger.FromInt32(0); } if (shiftWords > 2) { ret = ShortenArray(ret, retWordCount); } return new EInteger(retWordCount, ret, this.negative); } /** * Finds the square root of this instance's value, rounded down. * @return The square root of this object's value. Returns 0 if this value is 0 * or less. */ public EInteger Sqrt() { EInteger[] srrem = this.SqrtRemInternal(false); return srrem[0]; } /** * Calculates the square root and the remainder. * @return An array of two arbitrary-precision integers: the first integer is * the square root, and the second is the difference between this value * and the square of the first integer. Returns two zeros if this value * is 0 or less, or one and zero if this value equals 1. */ public EInteger[] SqrtRem() { return this.SqrtRemInternal(true); } /** * Subtracts an arbitrary-precision integer from this arbitrary-precision * integer. * @param subtrahend Another arbitrary-precision integer. * @return The difference of the two objects. * @throws java.lang.NullPointerException The parameter {@code subtrahend} is * null. */ public EInteger Subtract(EInteger subtrahend) { if (subtrahend == null) { throw new NullPointerException("subtrahend"); } return (this.wordCount == 0) ? subtrahend.Negate() : ((subtrahend.wordCount == 0) ? this : this.Add(subtrahend.Negate())); } /** * Returns a byte array of this integer's value. The byte array will take the * number's two' s-complement form (see {@link * com.upokecenter.numbers.EDecimal "Forms of numbers"}), using the * fewest bytes necessary to store its value unambiguously. If this * value is negative, the bits that appear beyond the most significant * bit of the number will be all ones. The resulting byte array can be * passed to the FromBytes() method (with the same byte order) to * reconstruct this integer's value. * @param littleEndian Either {@code true} or {@code false} . * @return A byte array. If this value is 0, returns a byte array with the * single element 0. */ public byte[] ToBytes(boolean littleEndian) { int sign = this.signum(); if (sign == 0) { return new byte[] { (byte)0 }; } if (sign > 0) { int byteCount = this.ByteCount(); int byteArrayLength = byteCount; if (this.GetUnsignedBit((byteCount * 8) - 1)) { ++byteArrayLength; } byte[] bytes = new byte[byteArrayLength]; int j = 0; for (int i = 0; i < byteCount; i += 2, j++) { int index = littleEndian ? i : bytes.length - 1 - i; int index2 = littleEndian ? i + 1 : bytes.length - 2 - i; bytes[index] = (byte)(this.words[j] & 0xff); if (index2 >= 0 && index2 < byteArrayLength) { bytes[index2] = (byte)((this.words[j] >> 8) & 0xff); } } return bytes; } else { short[] regdata = new short[this.words.length]; System.arraycopy(this.words, 0, regdata, 0, this.words.length); TwosComplement(regdata, 0, (int)regdata.length); int byteCount = regdata.length * 2; for (int i = regdata.length - 1; i >= 0; --i) { if (regdata[i] == ((short)0xffff)) { byteCount -= 2; } else if ((regdata[i] & 0xff80) == 0xff80) { // signed first byte, 0xff second --byteCount; break; } else if ((regdata[i] & 0x8000) == 0x8000) { // signed second byte break; } else { // unsigned second byte ++byteCount; break; } } if (byteCount == 0) { byteCount = 1; } byte[] bytes = new byte[byteCount]; bytes[littleEndian ? bytes.length - 1 : 0] = (byte)0xff; byteCount = Math.min(byteCount, regdata.length * 2); int j = 0; for (int i = 0; i < byteCount; i += 2, j++) { int index = littleEndian ? i : bytes.length - 1 - i; int index2 = littleEndian ? i + 1 : bytes.length - 2 - i; bytes[index] = (byte)(regdata[j] & 0xff); if (index2 >= 0 && index2 < byteCount) { bytes[index2] = (byte)((regdata[j] >> 8) & 0xff); } } return bytes; } } /** * Converts this object's value to a 32-bit signed integer, throwing an * exception if it can't fit. * @return A 32-bit signed integer. * @throws T:java.lang.ArithmeticException This object' s value is too big to fit a * 32-bit signed integer. */ public int ToInt32Checked() { int count = this.wordCount; if (count == 0) { return 0; } if (count > 2) { throw new ArithmeticException(); } if (count == 2 && (this.words[1] & 0x8000) != 0) { if (this.negative && this.words[1] == ((short)0x8000) && this.words[0] == 0) { return Integer.MIN_VALUE; } throw new ArithmeticException(); } return this.ToInt32Unchecked(); } /** * Converts this object's value to a 32-bit signed integer. If the value can't * fit in a 32-bit integer, returns the lower 32 bits of this object's * two' s-complement form (see {@link com.upokecenter.numbers.EDecimal * "Forms of numbers" }) (in which case the return value might have a * different sign than this object's value). * @return A 32-bit signed integer. */ public int ToInt32Unchecked() { int c = (int)this.wordCount; if (c == 0) { return 0; } int intRetValue = ((int)this.words[0]) & 0xffff; if (c > 1) { intRetValue |= (((int)this.words[1]) & 0xffff) << 16; } if (this.negative) { intRetValue = (intRetValue - 1); intRetValue = (~intRetValue); } return intRetValue; } /** * Converts this object's value to a 64-bit signed integer, throwing an * exception if it can't fit. * @return A 64-bit signed integer. * @throws T:java.lang.ArithmeticException This object' s value is too big to fit a * 64-bit signed integer. */ public long ToInt64Checked() { int count = this.wordCount; if (count == 0) { return (long)0; } if (count > 4) { throw new ArithmeticException(); } if (count == 4 && (this.words[3] & 0x8000) != 0) { if (this.negative && this.words[3] == ((short)0x8000) && this.words[2] == 0 && this.words[1] == 0 && this.words[0] == 0) { return Long.MIN_VALUE; } throw new ArithmeticException(); } return this.ToInt64Unchecked(); } /** * Converts this object's value to a 64-bit signed integer. If the value can't * fit in a 64-bit integer, returns the lower 64 bits of this object's * two' s-complement form (see {@link com.upokecenter.numbers.EDecimal * "Forms of numbers" }) (in which case the return value might have a * different sign than this object's value). * @return A 64-bit signed integer. */ public long ToInt64Unchecked() { int c = (int)this.wordCount; if (c == 0) { return (long)0; } long ivv = 0; int intRetValue = ((int)this.words[0]) & 0xffff; if (c > 1) { intRetValue |= (((int)this.words[1]) & 0xffff) << 16; } if (c > 2) { int intRetValue2 = ((int)this.words[2]) & 0xffff; if (c > 3) { intRetValue2 |= (((int)this.words[3]) & 0xffff) << 16; } if (this.negative) { if (intRetValue == 0) { intRetValue = (intRetValue - 1); intRetValue2 = (intRetValue2 - 1); } else { intRetValue = (intRetValue - 1); } intRetValue = (~intRetValue); intRetValue2 = (~intRetValue2); } ivv = ((long)intRetValue) & 0xffffffffL; ivv |= ((long)intRetValue2) << 32; return ivv; } ivv = ((long)intRetValue) & 0xffffffffL; if (this.negative) { ivv = -ivv; } return ivv; } private void ToRadixStringDecimal( StringBuilder outputSB, boolean optimize) { int i = 0; if (this.wordCount >= 100 && optimize) { StringBuilder rightBuilder = new StringBuilder(); int digits = this.wordCount * 3; EInteger pow = NumberUtility.FindPowerOfTen(digits); // DebugUtility.Log("---divrem " + (this.wordCount)); EInteger[] divrem = this.DivRem(pow); // DebugUtility.Log("" + (divrem[0].GetUnsignedBitLength()) + "," + // (// divrem[1].GetUnsignedBitLength())); divrem[0].ToRadixStringDecimal(outputSB, optimize); divrem[1].ToRadixStringDecimal(rightBuilder, optimize); for (i = rightBuilder.length(); i < digits; ++i) { outputSB.append('0'); } outputSB.append(rightBuilder.toString()); return; } if (this.HasSmallValue()) { outputSB.append(this.SmallValueToString()); return; } short[] tempReg = new short[this.wordCount]; System.arraycopy(this.words, 0, tempReg, 0, tempReg.length); int numWordCount = tempReg.length; while (numWordCount != 0 && tempReg[numWordCount - 1] == 0) { --numWordCount; } char[] s = new char[(numWordCount << 4) + 1]; while (numWordCount != 0) { if (numWordCount == 1 && tempReg[0] > 0 && tempReg[0] <= 0x7fff) { int rest = tempReg[0]; while (rest != 0) { // accurate approximation to rest/10 up to 43698, // and rest can go up to 32767 int newrest = (rest * 26215) >> 18; s[i++] = Digits.charAt(rest - (newrest * 10)); rest = newrest; } break; } if (numWordCount == 2 && tempReg[1] > 0 && tempReg[1] <= 0x7fff) { int rest = ((int)tempReg[0]) & 0xffff; rest |= (((int)tempReg[1]) & 0xffff) << 16; while (rest != 0) { int newrest = (rest < 43698) ? ((rest * 26215) >> 18) : (rest / 10); s[i++] = Digits.charAt(rest - (newrest * 10)); rest = newrest; } break; } else { int wci = numWordCount; short remainderShort = 0; int quo, rem; // Divide by 10000 while ((wci--) > 0) { int currentDividend = ((int)((((int)tempReg[wci]) & 0xffff) | ((int)remainderShort << 16))); quo = currentDividend / 10000; tempReg[wci] = ((short)quo); rem = currentDividend - (10000 * quo); remainderShort = ((short)rem); } int remainderSmall = remainderShort; // Recalculate word count while (numWordCount != 0 && tempReg[numWordCount - 1] == 0) { --numWordCount; } // accurate approximation to rest/10 up to 16388, // and rest can go up to 9999 int newrest = (remainderSmall * 3277) >> 15; s[i++] = Digits.charAt((int)(remainderSmall - (newrest * 10))); remainderSmall = newrest; newrest = (remainderSmall * 3277) >> 15; s[i++] = Digits.charAt((int)(remainderSmall - (newrest * 10))); remainderSmall = newrest; newrest = (remainderSmall * 3277) >> 15; s[i++] = Digits.charAt((int)(remainderSmall - (newrest * 10))); remainderSmall = newrest; s[i++] = Digits.charAt(remainderSmall); } } ReverseChars(s, 0, i); outputSB.append(s, 0, (0)+(i)); } private String ToUnoptString() { if (this.HasSmallValue()) { return this.SmallValueToString(); } StringBuilder sb = new StringBuilder(); if (this.negative) { sb.append('-'); } this.Abs().ToRadixStringDecimal(sb, false); return sb.toString(); } /** * Generates a string representing the value of this object, in the given * radix. * @param radix A radix from 2 through 36. For example, to generate a * hexadecimal (base-16) string, specify 16. To generate a decimal * (base-10) string, specify 10. * @return A string representing the value of this object. If this value is 0, * returns "0". If negative, the string will begin with a minus sign * ("-", U+002D). Depending on the radix, the string will use the basic * digits 0 to 9 (U + 0030 to U + 0039) and then the basic letters A to Z * (U + 0041 to U + 005A). For example, 0-9 in radix 10, and 0-9, then A-F * in radix 16. */ public String ToRadixString(int radix) { if (radix < 2) { throw new IllegalArgumentException("radix (" + radix + ") is less than 2"); } if (radix > 36) { throw new IllegalArgumentException("radix (" + radix + ") is more than 36"); } if (this.wordCount == 0) { return "0"; } if (radix == 10) { // Decimal if (this.HasSmallValue()) { return this.SmallValueToString(); } StringBuilder sb = new StringBuilder(); if (this.negative) { sb.append('-'); } this.Abs().ToRadixStringDecimal(sb, true); return sb.toString(); } if (radix == 16) { // Hex StringBuilder sb = new StringBuilder(); if (this.negative) { sb.append('-'); } boolean firstBit = true; int word = this.words[this.wordCount - 1]; for (int i = 0; i < 4; ++i) { if (!firstBit || (word & 0xf000) != 0) { sb.append(Digits.charAt((word >> 12) & 0x0f)); firstBit = false; } word <<= 4; } for (int j = this.wordCount - 2; j >= 0; --j) { word = this.words[j]; for (int i = 0; i < 4; ++i) { sb.append(Digits.charAt((word >> 12) & 0x0f)); word <<= 4; } } return sb.toString(); } if (radix == 2) { // Binary StringBuilder sb = new StringBuilder(); if (this.negative) { sb.append('-'); } boolean firstBit = true; int word = this.words[this.wordCount - 1]; for (int i = 0; i < 16; ++i) { if (!firstBit || (word & 0x8000) != 0) { sb.append((word & 0x8000) == 0 ? '0' : '1'); firstBit = false; } word <<= 1; } for (int j = this.wordCount - 2; j >= 0; --j) { word = this.words[j]; for (int i = 0; i < 16; ++i) { sb.append((word & 0x8000) == 0 ? '0' : '1'); word <<= 1; } } return sb.toString(); } else { // Other radixes short[] tempReg = new short[this.wordCount]; System.arraycopy(this.words, 0, tempReg, 0, tempReg.length); int numWordCount = tempReg.length; while (numWordCount != 0 && tempReg[numWordCount - 1] == 0) { --numWordCount; } int i = 0; char[] s = new char[(numWordCount << 4) + 1]; while (numWordCount != 0) { if (numWordCount == 1 && tempReg[0] > 0 && tempReg[0] <= 0x7fff) { int rest = tempReg[0]; while (rest != 0) { int newrest = rest / radix; s[i++] = Digits.charAt(rest - (newrest * radix)); rest = newrest; } break; } if (numWordCount == 2 && tempReg[1] > 0 && tempReg[1] <= 0x7fff) { int rest = ((int)tempReg[0]) & 0xffff; rest |= (((int)tempReg[1]) & 0xffff) << 16; while (rest != 0) { int newrest = rest / radix; s[i++] = Digits.charAt(rest - (newrest * radix)); rest = newrest; } break; } else { int wci = numWordCount; short remainderShort = 0; int quo, rem; // Divide by radix while ((wci--) > 0) { int currentDividend = ((int)((((int)tempReg[wci]) & 0xffff) | ((int)remainderShort << 16))); quo = currentDividend / radix; tempReg[wci] = ((short)quo); rem = currentDividend - (radix * quo); remainderShort = ((short)rem); } int remainderSmall = remainderShort; // Recalculate word count while (numWordCount != 0 && tempReg[numWordCount - 1] == 0) { --numWordCount; } s[i++] = Digits.charAt(remainderSmall); } } ReverseChars(s, 0, i); if (this.negative) { StringBuilder sb = new StringBuilder(i + 1); sb.append('-'); for (int j = 0; j < i; ++j) { sb.append(s[j]); } return sb.toString(); } return new String(s, 0, i); } } /** * Converts this object to a text string in base 10. * @return A string representation of this object. If negative, the string will * begin with a minus sign ("-", U+002D). The string will use the basic * digits 0 to 9 (U + 0030 to U + 0039). */ @Override public String toString() { if (this.isZero()) { return "0"; } return this.HasSmallValue() ? this.SmallValueToString() : this.ToRadixString(10); } private static int AddInternal( short[] c, int cstart, short[] words1, int astart, short[] words2, int bstart, int n) { { int u; u = 0; boolean evn = (n & 1) == 0; int valueNEven = evn ? n : n - 1; int i = 0; while (i < valueNEven) { u = (((int)words1[astart + i]) & 0xffff) + (((int)words2[bstart + i]) & 0xffff) + (short)(u >> 16); c[cstart + i] = (short)u; ++i; u = (((int)words1[astart + i]) & 0xffff) + (((int)words2[bstart + i]) & 0xffff) + (short)(u >> 16); c[cstart + i] = (short)u; ++i; } if (!evn) { u = (((int)words1[astart + valueNEven]) & 0xffff) + (((int)words2[bstart + valueNEven]) & 0xffff) + (short)(u >> 16); c[cstart + valueNEven] = (short)u; } return ((int)u >> 16) & 0xffff; } } private static int AddUnevenSize( short[] c, int cstart, short[] wordsBigger, int astart, int acount, short[] wordsSmaller, int bstart, int bcount) { { int u; u = 0; for (int i = 0; i < bcount; i += 1) { u = (((int)wordsBigger[astart + i]) & 0xffff) + (((int)wordsSmaller[bstart + i]) & 0xffff) + (short)(u >> 16); c[cstart + i] = (short)u; } for (int i = bcount; i < acount; i += 1) { u = (((int)wordsBigger[astart + i]) & 0xffff) + (short)(u >> 16); c[cstart + i] = (short)u; } return ((int)u >> 16) & 0xffff; } } private static int ApproxLogTenOfTwo(int bitlen) { int bitlenLow = bitlen & 0xffff; int bitlenHigh = (bitlen >> 16) & 0xffff; short resultLow = 0; short resultHigh = 0; { int p; short c; int d; p = bitlenLow * 0x84fb; d = ((int)p >> 16) & 0xffff; c = (short)d; d = ((int)d >> 16) & 0xffff; p = bitlenLow * 0x209a; p += ((int)c) & 0xffff; c = (short)p; d += ((int)p >> 16) & 0xffff; p = bitlenHigh * 0x84fb; p += ((int)c) & 0xffff; d += ((int)p >> 16) & 0xffff; c = (short)d; d = ((int)d >> 16) & 0xffff; p = bitlenLow * 0x9a; p += ((int)c) & 0xffff; c = (short)p; d += ((int)p >> 16) & 0xffff; p = bitlenHigh * 0x209a; p += ((int)c) & 0xffff; c = (short)p; d += ((int)p >> 16) & 0xffff; p = ((int)c) & 0xffff; c = (short)p; resultLow = c; c = (short)d; d = ((int)d >> 16) & 0xffff; p = bitlenHigh * 0x9a; p += ((int)c) & 0xffff; resultHigh = (short)p; int result = ((int)resultLow) & 0xffff; result |= (((int)resultHigh) & 0xffff) << 16; return (result & 0x7fffffff) >> 9; } } // Multiplies two operands of different sizes private static void AsymmetricMultiply( short[] resultArr, int resultStart, // uses words1Count + words2Count short[] tempArr, int tempStart, // uses words1Count + words2Count short[] words1, int words1Start, int words1Count, short[] words2, int words2Start, int words2Count) { // DebugUtility.Log("AsymmetricMultiply " + words1Count + " " + // words2Count + " [r=" + resultStart + " t=" + tempStart + " a=" + // words1Start + " b=" + words2Start + "]"); if (words1Count == words2Count) { if (words1Start == words2Start && words1 == words2) { // Both operands have the same value and the same word count RecursiveSquare( resultArr, resultStart, tempArr, tempStart, words1, words1Start, words1Count); } else if (words1Count == 2) { // Both operands have a word count of 2 BaselineMultiply2( resultArr, resultStart, words1, words1Start, words2, words2Start); } else { // Other cases where both operands have the same word count SameSizeMultiply( resultArr, resultStart, tempArr, tempStart, words1, words1Start, words2, words2Start, words1Count); } return; } if (words1Count > words2Count) { // Ensure that words1 is smaller by swapping if necessary short[] tmp1 = words1; words1 = words2; words2 = tmp1; int tmp3 = words1Start; words1Start = words2Start; words2Start = tmp3; int tmp2 = words1Count; words1Count = words2Count; words2Count = tmp2; } if (words1Count == 1 || (words1Count == 2 && words1[words1Start + 1] == 0)) { switch (words1[words1Start]) { case 0: // words1 is ValueZero, so result is 0 java.util.Arrays.fill(resultArr, resultStart, (resultStart)+(words2Count + 2), (short)0); return; case 1: System.arraycopy( words2, words2Start, resultArr, resultStart, (int)words2Count); resultArr[resultStart + words2Count] = (short)0; resultArr[resultStart + words2Count + 1] = (short)0; return; default: resultArr[resultStart + words2Count] = LinearMultiply( resultArr, resultStart, words2, words2Start, words1[words1Start], words2Count); resultArr[resultStart + words2Count + 1] = (short)0; return; } } if (words1Count == 2 && (words2Count & 1) == 0) { int a0 = ((int)words1[words1Start]) & 0xffff; int a1 = ((int)words1[words1Start + 1]) & 0xffff; resultArr[resultStart + words2Count] = (short)0; resultArr[resultStart + words2Count + 1] = (short)0; AtomicMultiplyOpt( resultArr, resultStart, a0, a1, words2, words2Start, 0, words2Count); AtomicMultiplyAddOpt( resultArr, resultStart, a0, a1, words2, words2Start, 2, words2Count); return; } if (words1Count <= 10 && words2Count <= 10) { SchoolbookMultiply( resultArr, resultStart, words1, words1Start, words1Count, words2, words2Start, words2Count); } else { int wordsRem = words2Count % words1Count; int evenmult = (words2Count / words1Count) & 1; int i; // DebugUtility.Log("counts=" + words1Count + "," + words2Count + // " res=" + (resultStart + words1Count) + " temp=" + (tempStart + // (words1Count << 1)) + " rem=" + wordsRem + " evenwc=" + evenmult); if (wordsRem == 0) { // words2Count is divisible by words1count if (evenmult == 0) { SameSizeMultiply( resultArr, resultStart, tempArr, tempStart, words1, words1Start, words2, words2Start, words1Count); System.arraycopy( resultArr, resultStart + words1Count, tempArr, (int)(tempStart + (words1Count << 1)), words1Count); for (i = words1Count << 1; i < words2Count; i += words1Count << 1) { SameSizeMultiply( tempArr, tempStart + words1Count + i, tempArr, tempStart, words1, words1Start, words2, words2Start + i, words1Count); } for (i = words1Count; i < words2Count; i += words1Count << 1) { SameSizeMultiply( resultArr, resultStart + i, tempArr, tempStart, words1, words1Start, words2, words2Start + i, words1Count); } } else { for (i = 0; i < words2Count; i += words1Count << 1) { SameSizeMultiply( resultArr, resultStart + i, tempArr, tempStart, words1, words1Start, words2, words2Start + i, words1Count); } for (i = words1Count; i < words2Count; i += words1Count << 1) { SameSizeMultiply( tempArr, tempStart + words1Count + i, tempArr, tempStart, words1, words1Start, words2, words2Start + i, words1Count); } } if ( AddInternal( resultArr, resultStart + words1Count, resultArr, resultStart + words1Count, tempArr, tempStart + (words1Count << 1), words2Count - words1Count) != 0) { Increment( resultArr, (int)(resultStart + words2Count), words1Count, (short)1); } } else if ((words1Count + words2Count) >= (words1Count << 2)) { // DebugUtility.Log("Chunked Linear Multiply long"); ChunkedLinearMultiply( resultArr, resultStart, tempArr, tempStart, words2, words2Start, words2Count, words1, words1Start, words1Count); } else if (words1Count + 1 == words2Count || (words1Count + 2 == words2Count && words2[words2Start + words2Count - 1] == 0)) { java.util.Arrays.fill(resultArr, resultStart, (resultStart)+(words1Count + words2Count), (short)0); // Multiply the low parts of each operand SameSizeMultiply( resultArr, resultStart, tempArr, tempStart, words1, words1Start, words2, words2Start, words1Count); // Multiply the high parts // while adding carry from the high part of the product short carry = LinearMultiplyAdd( resultArr, resultStart + words1Count, words1, words1Start, words2[words2Start + words1Count], words1Count); resultArr[resultStart + words1Count + words1Count] = carry; } else { short[] t2 = new short[words1Count << 2]; // DebugUtility.Log("Chunked Linear Multiply Short"); ChunkedLinearMultiply( resultArr, resultStart, t2, 0, words2, words2Start, words2Count, words1, words1Start, words1Count); } } } private static void AtomicMultiplyAddOpt( short[] c, int valueCstart, int valueA0, int valueA1, short[] words2, int words2Start, int istart, int iend) { short s; int d; int first1MinusFirst0 = ((int)valueA1 - valueA0) & 0xffff; valueA1 &= 0xffff; valueA0 &= 0xffff; { if (valueA1 >= valueA0) { for (int i = istart; i < iend; i += 4) { int b0 = ((int)words2[words2Start + i]) & 0xffff; int b1 = ((int)words2[words2Start + i + 1]) & 0xffff; int csi = valueCstart + i; if (b0 >= b1) { s = (short)0; d = first1MinusFirst0 * (((int)b0 - b1) & 0xffff); } else { s = (short)first1MinusFirst0; d = (((int)s) & 0xffff) * (((int)b0 - b1) & 0xffff); } int valueA0B0 = valueA0 * b0; int a0b0high = (valueA0B0 >> 16) & 0xffff; int tempInt; tempInt = valueA0B0 + (((int)c[csi]) & 0xffff); c[csi] = (short)(((int)tempInt) & 0xffff); int valueA1B1 = valueA1 * b1; int a1b1low = valueA1B1 & 0xffff; int a1b1high = ((int)(valueA1B1 >> 16)) & 0xffff; tempInt = (((int)(tempInt >> 16)) & 0xffff) + (((int)valueA0B0) & 0xffff) + (((int)d) & 0xffff) + a1b1low + (((int)c[csi + 1]) & 0xffff); c[csi + 1] = (short)(((int)tempInt) & 0xffff); tempInt = (((int)(tempInt >> 16)) & 0xffff) + a1b1low + a0b0high + (((int)(d >> 16)) & 0xffff) + a1b1high - (((int)s) & 0xffff) + (((int)c[csi + 2]) & 0xffff); c[csi + 2] = (short)(((int)tempInt) & 0xffff); tempInt = (((int)(tempInt >> 16)) & 0xffff) + a1b1high + (((int)c[csi + 3]) & 0xffff); c[csi + 3] = (short)(((int)tempInt) & 0xffff); if ((tempInt >> 16) != 0) { ++c[csi + 4]; c[csi + 5] += (short)((c[csi + 4] == 0) ? 1 : 0); } } } else { for (int i = istart; i < iend; i += 4) { int valueB0 = ((int)words2[words2Start + i]) & 0xffff; int valueB1 = ((int)words2[words2Start + i + 1]) & 0xffff; int csi = valueCstart + i; if (valueB0 > valueB1) { s = (short)(((int)valueB0 - valueB1) & 0xffff); d = first1MinusFirst0 * (((int)s) & 0xffff); } else { s = (short)0; d = (((int)valueA0 - valueA1) & 0xffff) * (((int)valueB1 - valueB0) & 0xffff); } int valueA0B0 = valueA0 * valueB0; int a0b0high = (valueA0B0 >> 16) & 0xffff; int tempInt; tempInt = valueA0B0 + (((int)c[csi]) & 0xffff); c[csi] = (short)(((int)tempInt) & 0xffff); int valueA1B1 = valueA1 * valueB1; int a1b1low = valueA1B1 & 0xffff; int a1b1high = (valueA1B1 >> 16) & 0xffff; tempInt = (((int)(tempInt >> 16)) & 0xffff) + (((int)valueA0B0) & 0xffff) + (((int)d) & 0xffff) + a1b1low + (((int)c[csi + 1]) & 0xffff); c[csi + 1] = (short)(((int)tempInt) & 0xffff); tempInt = (((int)(tempInt >> 16)) & 0xffff) + a1b1low + a0b0high + (((int)(d >> 16)) & 0xffff) + a1b1high - (((int)s) & 0xffff) + (((int)c[csi + 2]) & 0xffff); c[csi + 2] = (short)(((int)tempInt) & 0xffff); tempInt = (((int)(tempInt >> 16)) & 0xffff) + a1b1high + (((int)c[csi + 3]) & 0xffff); c[csi + 3] = (short)(((int)tempInt) & 0xffff); if ((tempInt >> 16) != 0) { ++c[csi + 4]; c[csi + 5] += (short)((c[csi + 4] == 0) ? 1 : 0); } } } } } private static void AtomicMultiplyOpt( short[] c, int valueCstart, int valueA0, int valueA1, short[] words2, int words2Start, int istart, int iend) { short s; int d; int first1MinusFirst0 = ((int)valueA1 - valueA0) & 0xffff; valueA1 &= 0xffff; valueA0 &= 0xffff; { if (valueA1 >= valueA0) { for (int i = istart; i < iend; i += 4) { int valueB0 = ((int)words2[words2Start + i]) & 0xffff; int valueB1 = ((int)words2[words2Start + i + 1]) & 0xffff; int csi = valueCstart + i; if (valueB0 >= valueB1) { s = (short)0; d = first1MinusFirst0 * (((int)valueB0 - valueB1) & 0xffff); } else { s = (short)first1MinusFirst0; d = (((int)s) & 0xffff) * (((int)valueB0 - valueB1) & 0xffff); } int valueA0B0 = valueA0 * valueB0; c[csi] = (short)(((int)valueA0B0) & 0xffff); int a0b0high = (valueA0B0 >> 16) & 0xffff; int valueA1B1 = valueA1 * valueB1; int tempInt; tempInt = a0b0high + (((int)valueA0B0) & 0xffff) + (((int)d) & 0xffff) + (((int)valueA1B1) & 0xffff); c[csi + 1] = (short)tempInt; tempInt = valueA1B1 + (((int)(tempInt >> 16)) & 0xffff) + a0b0high + (((int)(d >> 16)) & 0xffff) + (((int)(valueA1B1 >> 16)) & 0xffff) - (((int)s) & 0xffff); c[csi + 2] = (short)tempInt; tempInt >>= 16; c[csi + 3] = (short)tempInt; } } else { for (int i = istart; i < iend; i += 4) { int valueB0 = ((int)words2[words2Start + i]) & 0xffff; int valueB1 = ((int)words2[words2Start + i + 1]) & 0xffff; int csi = valueCstart + i; if (valueB0 > valueB1) { s = (short)(((int)valueB0 - valueB1) & 0xffff); d = first1MinusFirst0 * (((int)s) & 0xffff); } else { s = (short)0; d = (((int)valueA0 - valueA1) & 0xffff) * (((int)valueB1 - valueB0) & 0xffff); } int valueA0B0 = valueA0 * valueB0; int a0b0high = (valueA0B0 >> 16) & 0xffff; c[csi] = (short)(((int)valueA0B0) & 0xffff); int valueA1B1 = valueA1 * valueB1; int tempInt; tempInt = a0b0high + (((int)valueA0B0) & 0xffff) + (((int)d) & 0xffff) + (((int)valueA1B1) & 0xffff); c[csi + 1] = (short)tempInt; tempInt = valueA1B1 + (((int)(tempInt >> 16)) & 0xffff) + a0b0high + (((int)(d >> 16)) & 0xffff) + (((int)(valueA1B1 >> 16)) & 0xffff) - (((int)s) & 0xffff); c[csi + 2] = (short)tempInt; tempInt >>= 16; c[csi + 3] = (short)tempInt; } } } } //--------------------- // Baseline multiply //--------------------- private static void BaselineMultiply2( short[] result, int rstart, short[] words1, int astart, short[] words2, int bstart) { { int p; short c; int d; int a0 = ((int)words1[astart]) & 0xffff; int a1 = ((int)words1[astart + 1]) & 0xffff; int b0 = ((int)words2[bstart]) & 0xffff; int b1 = ((int)words2[bstart + 1]) & 0xffff; p = a0 * b0; c = (short)p; d = ((int)p >> 16) & 0xffff; result[rstart] = c; c = (short)d; d = ((int)d >> 16) & 0xffff; p = a0 * b1; p += ((int)c) & 0xffff; c = (short)p; d += ((int)p >> 16) & 0xffff; p = a1 * b0; p += ((int)c) & 0xffff; c = (short)p; d += ((int)p >> 16) & 0xffff; result[rstart + 1] = c; p = a1 * b1; p += d; result[rstart + 2] = (short)p; result[rstart + 3] = (short)(p >> 16); } } private static void BaselineMultiply4( short[] result, int rstart, short[] words1, int astart, short[] words2, int bstart) { { int SMask = ShortMask; int p; short c; int d; int a0 = ((int)words1[astart]) & SMask; int b0 = ((int)words2[bstart]) & SMask; p = a0 * b0; c = (short)p; d = ((int)p >> 16) & SMask; result[rstart] = c; c = (short)d; d = ((int)d >> 16) & SMask; p = a0 * (((int)words2[bstart + 1]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 1]) & SMask) * b0; p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; result[rstart + 1] = c; c = (short)d; d = ((int)d >> 16) & SMask; p = a0 * (((int)words2[bstart + 2]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 1]) & SMask) * (((int)words2[bstart + 1]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 2]) & SMask) * b0; p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; result[rstart + 2] = c; c = (short)d; d = ((int)d >> 16) & SMask; p = a0 * (((int)words2[bstart + 3]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 1]) & SMask) * (((int)words2[bstart + 2]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 2]) & SMask) * (((int)words2[bstart + 1]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 3]) & SMask) * b0; p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; result[rstart + 3] = c; c = (short)d; d = ((int)d >> 16) & SMask; p = (((int)words1[astart + 1]) & SMask) * (((int)words2[bstart + 3]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 2]) & SMask) * (((int)words2[bstart + 2]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 3]) & SMask) * (((int)words2[bstart + 1]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; result[rstart + 4] = c; c = (short)d; d = ((int)d >> 16) & SMask; p = (((int)words1[astart + 2]) & SMask) * (((int)words2[bstart + 3]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 3]) & SMask) * (((int)words2[bstart + 2]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; result[rstart + 5] = c; p = (((int)words1[astart + 3]) & SMask) * (((int)words2[bstart + 3]) & SMask); p += d; result[rstart + 6] = (short)p; result[rstart + 7] = (short)(p >> 16); } } private static void BaselineMultiply8( short[] result, int rstart, short[] words1, int astart, short[] words2, int bstart) { { int p; short c; int d; int SMask = ShortMask; p = (((int)words1[astart]) & SMask) * (((int)words2[bstart]) & SMask); c = (short)p; d = ((int)p >> 16) & SMask; result[rstart] = c; c = (short)d; d = ((int)d >> 16) & SMask; p = (((int)words1[astart]) & SMask) * (((int)words2[bstart + 1]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 1]) & SMask) * (((int)words2[bstart]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; result[rstart + 1] = c; c = (short)d; d = ((int)d >> 16) & SMask; p = (((int)words1[astart]) & SMask) * (((int)words2[bstart + 2]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 1]) & SMask) * (((int)words2[bstart + 1]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 2]) & SMask) * (((int)words2[bstart]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; result[rstart + 2] = c; c = (short)d; d = ((int)d >> 16) & SMask; p = (((int)words1[astart]) & SMask) * (((int)words2[bstart + 3]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 1]) & SMask) * (((int)words2[bstart + 2]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 2]) & SMask) * (((int)words2[bstart + 1]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 3]) & SMask) * (((int)words2[bstart]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; result[rstart + 3] = c; c = (short)d; d = ((int)d >> 16) & SMask; p = (((int)words1[astart]) & SMask) * (((int)words2[bstart + 4]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 1]) & SMask) * (((int)words2[bstart + 3]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 2]) & SMask) * (((int)words2[bstart + 2]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 3]) & SMask) * (((int)words2[bstart + 1]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 4]) & SMask) * (((int)words2[bstart]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; result[rstart + 4] = c; c = (short)d; d = ((int)d >> 16) & SMask; p = (((int)words1[astart]) & SMask) * (((int)words2[bstart + 5]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 1]) & SMask) * (((int)words2[bstart + 4]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 2]) & SMask) * (((int)words2[bstart + 3]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 3]) & SMask) * (((int)words2[bstart + 2]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 4]) & SMask) * (((int)words2[bstart + 1]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 5]) & SMask) * (((int)words2[bstart]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; result[rstart + 5] = c; c = (short)d; d = ((int)d >> 16) & SMask; p = (((int)words1[astart]) & SMask) * (((int)words2[bstart + 6]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 1]) & SMask) * (((int)words2[bstart + 5]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 2]) & SMask) * (((int)words2[bstart + 4]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 3]) & SMask) * (((int)words2[bstart + 3]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 4]) & SMask) * (((int)words2[bstart + 2]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 5]) & SMask) * (((int)words2[bstart + 1]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 6]) & SMask) * (((int)words2[bstart]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; result[rstart + 6] = c; c = (short)d; d = ((int)d >> 16) & SMask; p = (((int)words1[astart]) & SMask) * (((int)words2[bstart + 7]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 1]) & SMask) * (((int)words2[bstart + 6]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 2]) & SMask) * (((int)words2[bstart + 5]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 3]) & SMask) * (((int)words2[bstart + 4]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 4]) & SMask) * (((int)words2[bstart + 3]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 5]) & SMask) * (((int)words2[bstart + 2]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 6]) & SMask) * (((int)words2[bstart + 1]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 7]) & SMask) * (((int)words2[bstart]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; result[rstart + 7] = c; c = (short)d; d = ((int)d >> 16) & SMask; p = (((int)words1[astart + 1]) & SMask) * (((int)words2[bstart + 7]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 2]) & SMask) * (((int)words2[bstart + 6]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 3]) & SMask) * (((int)words2[bstart + 5]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 4]) & SMask) * (((int)words2[bstart + 4]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 5]) & SMask) * (((int)words2[bstart + 3]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 6]) & SMask) * (((int)words2[bstart + 2]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 7]) & SMask) * (((int)words2[bstart + 1]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; result[rstart + 8] = c; c = (short)d; d = ((int)d >> 16) & SMask; p = (((int)words1[astart + 2]) & SMask) * (((int)words2[bstart + 7]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 3]) & SMask) * (((int)words2[bstart + 6]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 4]) & SMask) * (((int)words2[bstart + 5]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 5]) & SMask) * (((int)words2[bstart + 4]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 6]) & SMask) * (((int)words2[bstart + 3]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 7]) & SMask) * (((int)words2[bstart + 2]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; result[rstart + 9] = c; c = (short)d; d = ((int)d >> 16) & SMask; p = (((int)words1[astart + 3]) & SMask) * (((int)words2[bstart + 7]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 4]) & SMask) * (((int)words2[bstart + 6]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 5]) & SMask) * (((int)words2[bstart + 5]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 6]) & SMask) * (((int)words2[bstart + 4]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 7]) & SMask) * (((int)words2[bstart + 3]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; result[rstart + 10] = c; c = (short)d; d = ((int)d >> 16) & SMask; p = (((int)words1[astart + 4]) & SMask) * (((int)words2[bstart + 7]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 5]) & SMask) * (((int)words2[bstart + 6]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 6]) & SMask) * (((int)words2[bstart + 5]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 7]) & SMask) * (((int)words2[bstart + 4]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; result[rstart + 11] = c; c = (short)d; d = ((int)d >> 16) & SMask; p = (((int)words1[astart + 5]) & SMask) * (((int)words2[bstart + 7]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 6]) & SMask) * (((int)words2[bstart + 6]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 7]) & SMask) * (((int)words2[bstart + 5]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; result[rstart + 12] = c; c = (short)d; d = ((int)d >> 16) & SMask; p = (((int)words1[astart + 6]) & SMask) * (((int)words2[bstart + 7]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; p = (((int)words1[astart + 7]) & SMask) * (((int)words2[bstart + 6]) & SMask); p += ((int)c) & SMask; c = (short)p; d += ((int)p >> 16) & SMask; result[rstart + 13] = c; p = (((int)words1[astart + 7]) & SMask) * (((int)words2[bstart + 7]) & SMask); p += d; result[rstart + 14] = (short)p; result[rstart + 15] = (short)(p >> 16); } } //----------------------------- // Baseline Square //----------------------------- private static void BaselineSquare2( short[] result, int rstart, short[] words1, int astart) { { int p; short c; int d; int e; p = (((int)words1[astart]) & 0xffff) * (((int)words1[astart]) & 0xffff); result[rstart] = (short)p; e = ((int)p >> 16) & 0xffff; p = (((int)words1[astart]) & 0xffff) * (((int)words1[astart + 1]) & 0xffff); c = (short)p; d = ((int)p >> 16) & 0xffff; d = (int)((d << 1) + (((int)c >> 15) & 1)); c <<= 1; e += ((int)c) & 0xffff; c = (short)e; e = d + (((int)e >> 16) & 0xffff); result[rstart + 1] = c; p = (((int)words1[astart + 1]) & 0xffff) * (((int)words1[astart + 1]) & 0xffff); p += e; result[rstart + 2] = (short)p; result[rstart + 3] = (short)(p >> 16); } } private static void BaselineSquare4( short[] result, int rstart, short[] words1, int astart) { { int p; short c; int d; int e; p = (((int)words1[astart]) & 0xffff) * (((int)words1[astart]) & 0xffff); result[rstart] = (short)p; e = ((int)p >> 16) & 0xffff; p = (((int)words1[astart]) & 0xffff) * (((int)words1[astart + 1]) & 0xffff); c = (short)p; d = ((int)p >> 16) & 0xffff; d = (int)((d << 1) + (((int)c >> 15) & 1)); c <<= 1; e += ((int)c) & 0xffff; c = (short)e; e = d + (((int)e >> 16) & 0xffff); result[rstart + 1] = c; p = (((int)words1[astart]) & 0xffff) * (((int)words1[astart + 2]) & 0xffff); c = (short)p; d = ((int)p >> 16) & 0xffff; d = (int)((d << 1) + (((int)c >> 15) & 1)); c <<= 1; p = (((int)words1[astart + 1]) & 0xffff) * (((int)words1[astart + 1]) & 0xffff); p += ((int)c) & 0xffff; c = (short)p; d += ((int)p >> 16) & 0xffff; e += ((int)c) & 0xffff; c = (short)e; e = d + (((int)e >> 16) & 0xffff); result[rstart + 2] = c; p = (((int)words1[astart]) & 0xffff) * (((int)words1[astart + 3]) & 0xffff); c = (short)p; d = ((int)p >> 16) & 0xffff; p = (((int)words1[astart + 1]) & 0xffff) * (((int)words1[astart + 2]) & 0xffff); p += ((int)c) & 0xffff; c = (short)p; d += ((int)p >> 16) & 0xffff; d = (int)((d << 1) + (((int)c >> 15) & 1)); c <<= 1; e += ((int)c) & 0xffff; c = (short)e; e = d + (((int)e >> 16) & 0xffff); result[rstart + 3] = c; p = (((int)words1[astart + 1]) & 0xffff) * (((int)words1[astart + 3]) & 0xffff); c = (short)p; d = ((int)p >> 16) & 0xffff; d = (int)((d << 1) + (((int)c >> 15) & 1)); c <<= 1; p = (((int)words1[astart + 2]) & 0xffff) * (((int)words1[astart + 2]) & 0xffff); p += ((int)c) & 0xffff; c = (short)p; d += ((int)p >> 16) & 0xffff; e += ((int)c) & 0xffff; c = (short)e; e = d + (((int)e >> 16) & 0xffff); result[rstart + 4] = c; p = (((int)words1[astart + 2]) & 0xffff) * (((int)words1[astart + 3]) & 0xffff); c = (short)p; d = ((int)p >> 16) & 0xffff; d = (int)((d << 1) + (((int)c >> 15) & 1)); c <<= 1; e += ((int)c) & 0xffff; c = (short)e; e = d + (((int)e >> 16) & 0xffff); result[rstart + (2 * 4) - 3] = c; p = (((int)words1[astart + 3]) & 0xffff) * (((int)words1[astart + 3]) & 0xffff); p += e; result[rstart + 6] = (short)p; result[rstart + 7] = (short)(p >> 16); } } private static void BaselineSquare8( short[] result, int rstart, short[] words1, int astart) { { int p; short c; int d; int e; p = (((int)words1[astart]) & 0xffff) * (((int)words1[astart]) & 0xffff); result[rstart] = (short)p; e = ((int)p >> 16) & 0xffff; p = (((int)words1[astart]) & 0xffff) * (((int)words1[astart + 1]) & 0xffff); c = (short)p; d = ((int)p >> 16) & 0xffff; d = (int)((d << 1) + (((int)c >> 15) & 1)); c <<= 1; e += ((int)c) & 0xffff; c = (short)e; e = d + (((int)e >> 16) & 0xffff); result[rstart + 1] = c; p = (((int)words1[astart]) & 0xffff) * (((int)words1[astart + 2]) & 0xffff); c = (short)p; d = ((int)p >> 16) & 0xffff; d = (int)((d << 1) + (((int)c >> 15) & 1)); c <<= 1; p = (((int)words1[astart + 1]) & 0xffff) * (((int)words1[astart + 1]) & 0xffff); p += ((int)c) & 0xffff; c = (short)p; d += ((int)p >> 16) & 0xffff; e += ((int)c) & 0xffff; c = (short)e; e = d + (((int)e >> 16) & 0xffff); result[rstart + 2] = c; p = (((int)words1[astart]) & 0xffff) * (((int)words1[astart + 3]) & 0xffff); c = (short)p; d = ((int)p >> 16) & 0xffff; p = (((int)words1[astart + 1]) & 0xffff) * (((int)words1[astart + 2]) & 0xffff); p += ((int)c) & 0xffff; c = (short)p; d += ((int)p >> 16) & 0xffff; d = (int)((d << 1) + (((int)c >> 15) & 1)); c <<= 1; e += ((int)c) & 0xffff; c = (short)e; e = d + (((int)e >> 16) & 0xffff); result[rstart + 3] = c; p = (((int)words1[astart]) & 0xffff) * (((int)words1[astart + 4]) & 0xffff); c = (short)p; d = ((int)p >> 16) & 0xffff; p = (((int)words1[astart + 1]) & 0xffff) * (((int)words1[astart + 3]) & 0xffff); p += ((int)c) & 0xffff; c = (short)p; d += ((int)p >> 16) & 0xffff; d = (int)((d << 1) + (((int)c >> 15) & 1)); c <<= 1; p = (((int)words1[astart + 2]) & 0xffff) * (((int)words1[astart + 2]) & 0xffff); p += ((int)c) & 0xffff; c = (short)p; d += ((int)p >> 16) & 0xffff; e += ((int)c) & 0xffff; c = (short)e; e = d + (((int)e >> 16) & 0xffff); result[rstart + 4] = c; p = (((int)words1[astart]) & 0xffff) * (((int)words1[astart + 5]) & 0xffff); c = (short)p; d = ((int)p >> 16) & 0xffff; p = (((int)words1[astart + 1]) & 0xffff) * (((int)words1[astart + 4]) & 0xffff); p += ((int)c) & 0xffff; c = (short)p; d += ((int)p >> 16) & 0xffff; p = (((int)words1[astart + 2]) & 0xffff) * (((int)words1[astart + 3]) & 0xffff); p += ((int)c) & 0xffff; c = (short)p; d += ((int)p >> 16) & 0xffff; d = (int)((d << 1) + (((int)c >> 15) & 1)); c <<= 1; e += ((int)c) & 0xffff; c = (short)e; e = d + (((int)e >> 16) & 0xffff); result[rstart + 5] = c; p = (((int)words1[astart]) & 0xffff) * (((int)words1[astart + 6]) & 0xffff); c = (short)p; d = ((int)p >> 16) & 0xffff; p = (((int)words1[astart + 1]) & 0xffff) * (((int)words1[astart + 5]) & 0xffff); p += ((int)c) & 0xffff; c = (short)p; d += ((int)p >> 16) & 0xffff; p = (((int)words1[astart + 2]) & 0xffff) * (((int)words1[astart + 4]) & 0xffff); p += ((int)c) & 0xffff; c = (short)p; d += ((int)p >> 16) & 0xffff; d = (int)((d << 1) + (((int)c >> 15) & 1)); c <<= 1; p = (((int)words1[astart + 3]) & 0xffff) * (((int)words1[astart + 3]) & 0xffff); p += ((int)c) & 0xffff; c = (short)p; d += ((int)p >> 16) & 0xffff; e += ((int)c) & 0xffff; c = (short)e; e = d + (((int)e >> 16) & 0xffff); result[rstart + 6] = c; p = (((int)words1[astart]) & 0xffff) * (((int)words1[astart + 7]) & 0xffff); c = (short)p; d = ((int)p >> 16) & 0xffff; p = (((int)words1[astart + 1]) & 0xffff) * (((int)words1[astart + 6]) & 0xffff); p += ((int)c) & 0xffff; c = (short)p; d += ((int)p >> 16) & 0xffff; p = (((int)words1[astart + 2]) & 0xffff) * (((int)words1[astart + 5]) & 0xffff); p += ((int)c) & 0xffff; c = (short)p; d += ((int)p >> 16) & 0xffff; p = (((int)words1[astart + 3]) & 0xffff) * (((int)words1[astart + 4]) & 0xffff); p += ((int)c) & 0xffff; c = (short)p; d += ((int)p >> 16) & 0xffff; d = (int)((d << 1) + (((int)c >> 15) & 1)); c <<= 1; e += ((int)c) & 0xffff; c = (short)e; e = d + (((int)e >> 16) & 0xffff); result[rstart + 7] = c; p = (((int)words1[astart + 1]) & 0xffff) * (((int)words1[astart + 7]) & 0xffff); c = (short)p; d = ((int)p >> 16) & 0xffff; p = (((int)words1[astart + 2]) & 0xffff) * (((int)words1[astart + 6]) & 0xffff); p += ((int)c) & 0xffff; c = (short)p; d += ((int)p >> 16) & 0xffff; p = (((int)words1[astart + 3]) & 0xffff) * (((int)words1[astart + 5]) & 0xffff); p += ((int)c) & 0xffff; c = (short)p; d += ((int)p >> 16) & 0xffff; d = (int)((d << 1) + (((int)c >> 15) & 1)); c <<= 1; p = (((int)words1[astart + 4]) & 0xffff) * (((int)words1[astart + 4]) & 0xffff); p += ((int)c) & 0xffff; c = (short)p; d += ((int)p >> 16) & 0xffff; e += ((int)c) & 0xffff; c = (short)e; e = d + (((int)e >> 16) & 0xffff); result[rstart + 8] = c; p = (((int)words1[astart + 2]) & 0xffff) * (((int)words1[astart + 7]) & 0xffff); c = (short)p; d = ((int)p >> 16) & 0xffff; p = (((int)words1[astart + 3]) & 0xffff) * (((int)words1[astart + 6]) & 0xffff); p += ((int)c) & 0xffff; c = (short)p; d += ((int)p >> 16) & 0xffff; p = (((int)words1[astart + 4]) & 0xffff) * (((int)words1[astart + 5]) & 0xffff); p += ((int)c) & 0xffff; c = (short)p; d += ((int)p >> 16) & 0xffff; d = (int)((d << 1) + (((int)c >> 15) & 1)); c <<= 1; e += ((int)c) & 0xffff; c = (short)e; e = d + (((int)e >> 16) & 0xffff); result[rstart + 9] = c; p = (((int)words1[astart + 3]) & 0xffff) * (((int)words1[astart + 7]) & 0xffff); c = (short)p; d = ((int)p >> 16) & 0xffff; p = (((int)words1[astart + 4]) & 0xffff) * (((int)words1[astart + 6]) & 0xffff); p += ((int)c) & 0xffff; c = (short)p; d += ((int)p >> 16) & 0xffff; d = (int)((d << 1) + (((int)c >> 15) & 1)); c <<= 1; p = (((int)words1[astart + 5]) & 0xffff) * (((int)words1[astart + 5]) & 0xffff); p += ((int)c) & 0xffff; c = (short)p; d += ((int)p >> 16) & 0xffff; e += ((int)c) & 0xffff; c = (short)e; e = d + (((int)e >> 16) & 0xffff); result[rstart + 10] = c; p = (((int)words1[astart + 4]) & 0xffff) * (((int)words1[astart + 7]) & 0xffff); c = (short)p; d = ((int)p >> 16) & 0xffff; p = (((int)words1[astart + 5]) & 0xffff) * (((int)words1[astart + 6]) & 0xffff); p += ((int)c) & 0xffff; c = (short)p; d += ((int)p >> 16) & 0xffff; d = (int)((d << 1) + (((int)c >> 15) & 1)); c <<= 1; e += ((int)c) & 0xffff; c = (short)e; e = d + (((int)e >> 16) & 0xffff); result[rstart + 11] = c; p = (((int)words1[astart + 5]) & 0xffff) * (((int)words1[astart + 7]) & 0xffff); c = (short)p; d = ((int)p >> 16) & 0xffff; d = (int)((d << 1) + (((int)c >> 15) & 1)); c <<= 1; p = (((int)words1[astart + 6]) & 0xffff) * (((int)words1[astart + 6]) & 0xffff); p += ((int)c) & 0xffff; c = (short)p; d += ((int)p >> 16) & 0xffff; e += ((int)c) & 0xffff; c = (short)e; e = d + (((int)e >> 16) & 0xffff); result[rstart + 12] = c; p = (((int)words1[astart + 6]) & 0xffff) * (((int)words1[astart + 7]) & 0xffff); c = (short)p; d = ((int)p >> 16) & 0xffff; d = (int)((d << 1) + (((int)c >> 15) & 1)); c <<= 1; e += ((int)c) & 0xffff; c = (short)e; e = d + (((int)e >> 16) & 0xffff); result[rstart + 13] = c; p = (((int)words1[astart + 7]) & 0xffff) * (((int)words1[astart + 7]) & 0xffff); p += e; result[rstart + 14] = (short)p; result[rstart + 15] = (short)(p >> 16); } } private static int BitPrecision(short numberValue) { if (numberValue == 0) { return 0; } int i = 16; { if ((numberValue >> 8) == 0) { numberValue <<= 8; i -= 8; } if ((numberValue >> 12) == 0) { numberValue <<= 4; i -= 4; } if ((numberValue >> 14) == 0) { numberValue <<= 2; i -= 2; } if ((numberValue >> 15) == 0) { --i; } } return i; } private static int BitsToWords(int bitCount) { return (bitCount + 15) >> 4; } private static void ChunkedLinearMultiply( short[] productArr, int cstart, short[] tempArr, int tempStart, // uses bcount*4 space short[] words1, int astart, int acount, // Equal size or longer short[] words2, int bstart, int bcount) { { int carryPos = 0; // Set carry to ValueZero java.util.Arrays.fill(productArr, cstart, (cstart)+(bcount), (short)0); for (int i = 0; i < acount; i += bcount) { int diff = acount - i; if (diff > bcount) { SameSizeMultiply( tempArr, tempStart, tempArr, tempStart + bcount + bcount, words1, astart + i, words2, bstart, bcount); // Add carry AddUnevenSize( tempArr, tempStart, tempArr, tempStart, bcount + bcount, productArr, cstart + carryPos, bcount); // Copy product and carry System.arraycopy( tempArr, tempStart, productArr, cstart + i, bcount + bcount); carryPos += bcount; } else { AsymmetricMultiply( tempArr, tempStart, // uses diff + bcount space tempArr, tempStart + diff + bcount, // uses diff + bcount words1, astart + i, diff, words2, bstart, bcount); // Add carry AddUnevenSize( tempArr, tempStart, tempArr, tempStart, diff + bcount, productArr, cstart + carryPos, bcount); // Copy product without carry System.arraycopy( tempArr, tempStart, productArr, cstart + i, diff + bcount); } } } } private static short[] CleanGrow(short[] a, int size) { if (size > a.length) { short[] newa = new short[size]; System.arraycopy(a, 0, newa, 0, a.length); return newa; } return a; } private static int Compare( short[] words1, int astart, short[] words2, int bstart, int n) { while ((n--) != 0) { int an = ((int)words1[astart + n]) & 0xffff; int bn = ((int)words2[bstart + n]) & 0xffff; if (an > bn) { return 1; } if (an < bn) { return -1; } } return 0; } private static int CompareWithWords1IsOneBigger( short[] words1, int astart, short[] words2, int bstart, int words1Count) { // NOTE: Assumes that words2's count is 1 less if (words1[astart + words1Count - 1] != 0) { return 1; } int w1c = words1Count; --w1c; while ((w1c--) != 0) { int an = ((int)words1[astart + w1c]) & 0xffff; int bn = ((int)words2[bstart + w1c]) & 0xffff; if (an > bn) { return 1; } if (an < bn) { return -1; } } return 0; } private static int CountWords(short[] array) { int n = array.length; while (n != 0 && array[n - 1] == 0) { --n; } return (int)n; } private static int CountWords(short[] array, int pos, int len) { int n = len; while (n != 0 && array[pos + n - 1] == 0) { --n; } return (int)n; } private static int Decrement( short[] words1, int words1Start, int n, short words2) { { short tmp = words1[words1Start]; words1[words1Start] = (short)(tmp - words2); if ((((int)words1[words1Start]) & 0xffff) <= (((int)tmp) & 0xffff)) { return 0; } for (int i = 1; i < n; ++i) { tmp = words1[words1Start + i]; --words1[words1Start + i]; if (tmp != 0) { return 0; } } return 1; } } private static short Divide32By16( int dividendLow, short divisorShort, boolean returnRemainder) { int tmpInt; int dividendHigh = 0; int intDivisor = ((int)divisorShort) & 0xffff; for (int i = 0; i < 32; ++i) { tmpInt = dividendHigh >> 31; dividendHigh <<= 1; dividendHigh = ((int)(dividendHigh | ((int)((dividendLow >> 31) & 1)))); dividendLow <<= 1; tmpInt |= dividendHigh; // unsigned greater-than-or-equal check if (((tmpInt >> 31) != 0) || (tmpInt >= intDivisor)) { { dividendHigh -= intDivisor; ++dividendLow; } } } return returnRemainder ? ((short)(((int)dividendHigh) & 0xffff)) : ((short)(((int)dividendLow) & 0xffff)); } private static short DivideUnsigned(int x, short y) { if ((x >> 31) == 0) { // x is already nonnegative int iy = ((int)y) & 0xffff; return (short)((int)x / iy); } else { long longX = ((long)x) & 0xffffffffL; int iy = ((int)y) & 0xffff; return (short)(longX / iy); } } private static void FastDivide( short[] quotientReg, short[] dividendReg, int count, short divisorSmall) { switch (divisorSmall) { case 2: FastDivideAndRemainderTwo(quotientReg, 0, dividendReg, 0, count); break; case 10: FastDivideAndRemainderTen(quotientReg, 0, dividendReg, 0, count); break; default: FastDivideAndRemainder( quotientReg, 0, dividendReg, 0, count, divisorSmall); break; } } private static short FastDivideAndRemainderTwo( short[] quotientReg, int quotientStart, short[] dividendReg, int dividendStart, int count) { int quo; int rem = 0; int currentDividend; int ds = dividendStart + count - 1; int qs = quotientStart + count - 1; for (int i = 0; i < count; ++i) { currentDividend = ((int)dividendReg[ds]) & 0xffff; currentDividend |= rem << 16; quo = currentDividend >> 1; quotientReg[qs] = ((short)quo); rem = currentDividend & 1; --ds; --qs; } return (short)rem; } private static short FastDivideAndRemainderTen( short[] quotientReg, int quotientStart, short[] dividendReg, int dividendStart, int count) { int quo; int rem = 0; int currentDividend; int ds = dividendStart + count - 1; int qs = quotientStart + count - 1; for (int i = 0; i < count; ++i) { currentDividend = ((int)dividendReg[ds]) & 0xffff; currentDividend |= rem << 16; quo = (currentDividend < 43698) ? ((currentDividend * 26215) >> 18) : (currentDividend / 10); quotientReg[qs] = ((short)quo); rem = currentDividend - (10 * quo); --ds; --qs; } return (short)rem; } private static short FastDivideAndRemainder( short[] quotientReg, int quotientStart, short[] dividendReg, int dividendStart, int count, short divisorSmall) { int idivisor = ((int)divisorSmall) & 0xffff; int quo; int rem = 0; int ds = dividendStart + count - 1; int qs = quotientStart + count - 1; int currentDividend; if (idivisor >= 0x8000) { for (int i = 0; i < count; ++i) { currentDividend = ((int)dividendReg[ds]) & 0xffff; currentDividend |= rem << 16; if ((currentDividend >> 31) == 0) { quo = currentDividend / idivisor; quotientReg[qs] = ((short)quo); rem = currentDividend - (idivisor * quo); } else { quo = ((int)DivideUnsigned( currentDividend, divisorSmall)) & 0xffff; quotientReg[qs] = ((short)quo); rem = (currentDividend - (idivisor * quo)); } --ds; --qs; } } else { for (int i = 0; i < count; ++i) { currentDividend = ((int)dividendReg[ds]) & 0xffff; currentDividend |= rem << 16; quo = currentDividend / idivisor; quotientReg[qs] = ((short)quo); rem = currentDividend - (idivisor * quo); --ds; --qs; } } return (short)rem; } private static short FastRemainder( short[] dividendReg, int count, short divisorSmall) { int i = count; short remainder = 0; while ((i--) > 0) { remainder = RemainderUnsigned( MakeUint(dividendReg[i], remainder), divisorSmall); } return remainder; } private static short GetHighHalfAsBorrow(int val) { return ((short)(0 - ((val >> 16) & 0xffff))); } private static int GetLowHalf(int val) { return val & 0xffff; } private static int GetUnsignedBitLengthEx(int numberValue, int wordCount) { int wc = wordCount; if (wc != 0) { wc = (wc - 1) << 4; if (numberValue == 0) { return wc; } wc += 16; { if ((numberValue >> 8) == 0) { numberValue <<= 8; wc -= 8; } if ((numberValue >> 12) == 0) { numberValue <<= 4; wc -= 4; } if ((numberValue >> 14) == 0) { numberValue <<= 2; wc -= 2; } if ((numberValue >> 15) == 0) { --wc; } } return wc; } return 0; } private static short[] GrowForCarry(short[] a, short carry) { int oldLength = a.length; short[] ret = CleanGrow(a, oldLength + 1); ret[oldLength] = carry; return ret; } private static int Increment( short[] words1, int words1Start, int n, short words2) { { short tmp = words1[words1Start]; words1[words1Start] = (short)(tmp + words2); if ((((int)words1[words1Start]) & 0xffff) >= (((int)tmp) & 0xffff)) { return 0; } for (int i = 1; i < n; ++i) { ++words1[words1Start + i]; if (words1[words1Start + i] != 0) { return 0; } } return 1; } } private static short LinearMultiply( short[] productArr, int cstart, short[] words1, int astart, short words2, int n) { { short carry = 0; int bint = ((int)words2) & 0xffff; for (int i = 0; i < n; ++i) { int p; p = (((int)words1[astart + i]) & 0xffff) * bint; p += ((int)carry) & 0xffff; productArr[cstart + i] = (short)p; carry = (short)(p >> 16); } return carry; } } private static short LinearMultiplyAdd( short[] productArr, int cstart, short[] words1, int astart, short words2, int n) { short carry = 0; int bint = ((int)words2) & 0xffff; for (int i = 0; i < n; ++i) { int p; p = ((((int)words1[astart + i]) & 0xffff) * bint); p = (p + (((int)carry) & 0xffff)); p = (p + (((int)productArr[cstart + i]) & 0xffff)); productArr[cstart + i] = ((short)p); carry = (short)(p >> 16); } return carry; } private static int MakeUint(short first, short second) { return ((int)((((int)first) & 0xffff) | ((int)second << 16))); } private static void RecursiveSquare( short[] resultArr, int resultStart, short[] tempArr, int tempStart, short[] words1, int words1Start, int count) { if (count <= RecursionLimit) { switch (count) { case 2: BaselineSquare2(resultArr, resultStart, words1, words1Start); break; case 4: BaselineSquare4(resultArr, resultStart, words1, words1Start); break; case 8: BaselineSquare8(resultArr, resultStart, words1, words1Start); break; default: SchoolbookSquare( resultArr, resultStart, words1, words1Start, count); break; } } else if ((count & 1) == 0) { int count2 = count >> 1; RecursiveSquare( resultArr, resultStart, tempArr, tempStart + count, words1, words1Start, count2); RecursiveSquare( resultArr, resultStart + count, tempArr, tempStart + count, words1, words1Start + count2, count2); SameSizeMultiply( tempArr, tempStart, tempArr, tempStart + count, words1, words1Start, words1, words1Start + count2, count2); int carry = AddInternal( resultArr, resultStart + count2, resultArr, resultStart + count2, tempArr, tempStart, count); carry += AddInternal( resultArr, resultStart + count2, resultArr, resultStart + count2, tempArr, tempStart, count); Increment( resultArr, (int)(resultStart + count + count2), count2, (short)carry); } else { SameSizeMultiply( resultArr, resultStart, tempArr, tempStart, words1, words1Start, words1, words1Start, count); } } private static short RemainderUnsigned(int x, short y) { { int iy = ((int)y) & 0xffff; return ((x >> 31) == 0) ? ((short)(((int)x % iy) & 0xffff)) : Divide32By16(x, y, true); } } private static void ReverseChars(char[] chars, int offset, int length) { int half = length >> 1; int right = offset + length - 1; for (int i = 0; i < half; i++, right--) { char value = chars[offset + i]; chars[offset + i] = chars[right]; chars[right] = value; } } // NOTE: Renamed from RecursiveMultiply to better show that // this function only takes operands of the same size, as opposed // to AsymmetricMultiply. private static void SameSizeMultiply( short[] resultArr, // size 2*count int resultStart, short[] tempArr, // size 2*count int tempStart, short[] words1, int words1Start, // size count short[] words2, int words2Start, // size count int count) { // DebugUtility.Log("RecursiveMultiply " + count + " " + count + // " [r=" + resultStart + " t=" + tempStart + " a=" + words1Start + // " b=" + words2Start + "]"); if (count <= RecursionLimit) { switch (count) { case 2: BaselineMultiply2( resultArr, resultStart, words1, words1Start, words2, words2Start); break; case 4: BaselineMultiply4( resultArr, resultStart, words1, words1Start, words2, words2Start); break; case 8: BaselineMultiply8( resultArr, resultStart, words1, words1Start, words2, words2Start); break; default: SchoolbookMultiply( resultArr, resultStart, words1, words1Start, count, words2, words2Start, count); break; } } else { int countA = count; while (countA != 0 && words1[words1Start + countA - 1] == 0) { --countA; } int countB = count; while (countB != 0 && words2[words2Start + countB - 1] == 0) { --countB; } int offset2For1 = 0; int offset2For2 = 0; if (countA == 0 || countB == 0) { // words1 or words2 is empty, so result is 0 java.util.Arrays.fill(resultArr, resultStart, (resultStart)+(count << 1), (short)0); return; } // Split words1 and words2 in two parts each // Words1 is split into HighA and LowA // Words2 is split into HighB and LowB if ((count & 1) == 0) { // Count is even, so each part will be equal size int count2 = count >> 1; if (countA <= count2 && countB <= count2) { // Both words1 and words2 are smaller than half the // count (their high parts are 0) // DebugUtility.Log("Can be smaller: " + AN + "," + BN + "," + // (count2)); java.util.Arrays.fill(resultArr, resultStart + count, (resultStart + count)+(count), (short)0); if (count2 == 8) { BaselineMultiply8( resultArr, resultStart, words1, words1Start, words2, words2Start); } else { SameSizeMultiply( resultArr, resultStart, tempArr, tempStart, words1, words1Start, words2, words2Start, count2); } return; } int resultMediumHigh = resultStart + count; int resultHigh = resultMediumHigh + count2; int resultMediumLow = resultStart + count2; int tsn = tempStart + count; // Find the part of words1 with the higher value // so we can compute the absolute value offset2For1 = Compare( words1, words1Start, words1, words1Start + count2, count2) > 0 ? 0 : count2; int tmpvar = (int)(words1Start + (count2 ^ offset2For1)); // Abs(LowA - HighA) SubtractInternal( resultArr, resultStart, words1, words1Start + offset2For1, words1, tmpvar, count2); // Find the part of words2 with the higher value // so we can compute the absolute value offset2For2 = Compare( words2, words2Start, words2, words2Start + count2, count2) > 0 ? 0 : count2; // Abs(LowB - HighB) int tmp = words2Start + (count2 ^ offset2For2); SubtractInternal( resultArr, resultMediumLow, words2, words2Start + offset2For2, words2, tmp, count2); // Medium-high/high result = HighA * HighB SameSizeMultiply( resultArr, resultMediumHigh, tempArr, tsn, words1, words1Start + count2, words2, words2Start + count2, count2); // Temp = Abs(LowA-HighA).Multiply(Abs)(LowB-HighB) SameSizeMultiply( tempArr, tempStart, tempArr, tsn, resultArr, resultStart, resultArr, resultMediumLow, count2); // Low/Medium-low result = LowA * LowB SameSizeMultiply( resultArr, resultStart, tempArr, tsn, words1, words1Start, words2, words2Start, count2); // Medium high result = Low(HighA * HighB) + High(LowA * LowB) int c2 = AddInternal( resultArr, resultMediumHigh, resultArr, resultMediumHigh, resultArr, resultMediumLow, count2); int c3 = c2; // Medium low result = Low(HighA * HighB) + High(LowA * LowB) + // Low(LowA * LowB) c2 += AddInternal( resultArr, resultMediumLow, resultArr, resultMediumHigh, resultArr, resultStart, count2); // Medium high result = Low(HighA * HighB) + High(LowA * LowB) + // High(HighA * HighB) c3 += AddInternal( resultArr, resultMediumHigh, resultArr, resultMediumHigh, resultArr, resultHigh, count2); if (offset2For1 == offset2For2) { // If high parts of both words were greater // than their low parts // or if low parts of both words were greater // than their high parts // Medium low/Medium high result = Medium low/Medium high result // - Low(Temp) c3 -= SubtractInternal( resultArr, resultMediumLow, resultArr, resultMediumLow, tempArr, tempStart, count); } else { // Medium low/Medium high result = Medium low/Medium high result // + Low(Temp) c3 += AddInternal( resultArr, resultMediumLow, resultArr, resultMediumLow, tempArr, tempStart, count); } // Add carry c3 += Increment(resultArr, resultMediumHigh, count2, (short)c2); if (c3 != 0) { Increment(resultArr, resultHigh, count2, (short)c3); } } else { // Count is odd, high part will be 1 shorter int countHigh = count >> 1; // Shorter part int countLow = count - countHigh; // Longer part offset2For1 = CompareWithWords1IsOneBigger( words1, words1Start, words1, words1Start + countLow, countLow) > 0 ? 0 : countLow; // Abs(LowA - HighA) if (offset2For1 == 0) { SubtractWords1IsOneBigger( resultArr, resultStart, words1, words1Start, words1, words1Start + countLow, countLow); } else { SubtractWords2IsOneBigger( resultArr, resultStart, words1, words1Start + countLow, words1, words1Start, countLow); } offset2For2 = CompareWithWords1IsOneBigger( words2, words2Start, words2, words2Start + countLow, countLow) > 0 ? 0 : countLow; // Abs(LowB, HighB) if (offset2For2 == 0) { SubtractWords1IsOneBigger( tempArr, tempStart, words2, words2Start, words2, words2Start + countLow, countLow); } else { SubtractWords2IsOneBigger( tempArr, tempStart, words2, words2Start + countLow, words2, words2Start, countLow); } // Temp = Abs(LowA-HighA).Multiply(Abs)(LowB-HighB) int shorterOffset = countHigh << 1; int longerOffset = countLow << 1; SameSizeMultiply( tempArr, tempStart + shorterOffset, resultArr, resultStart + shorterOffset, resultArr, resultStart, tempArr, tempStart, countLow); // Save part of temp since temp will overlap in part // in the Low/Medium low result multiply short resultTmp0 = tempArr[tempStart + shorterOffset]; short resultTmp1 = tempArr[tempStart + shorterOffset + 1]; // Medium high/high result = HighA * HighB SameSizeMultiply( resultArr, resultStart + longerOffset, resultArr, resultStart, words1, words1Start + countLow, words2, words2Start + countLow, countHigh); // Low/Medium low result = LowA * LowB SameSizeMultiply( resultArr, resultStart, tempArr, tempStart, words1, words1Start, words2, words2Start, countLow); // Restore part of temp tempArr[tempStart + shorterOffset] = resultTmp0; tempArr[tempStart + shorterOffset + 1] = resultTmp1; int countMiddle = countLow << 1; // Medium high result = Low(HighA * HighB) + High(LowA * LowB) int c2 = AddInternal( resultArr, resultStart + countMiddle, resultArr, resultStart + countMiddle, resultArr, resultStart + countLow, countLow); int c3 = c2; // Medium low result = Low(HighA * HighB) + High(LowA * LowB) + // Low(LowA * LowB) c2 += AddInternal( resultArr, resultStart + countLow, resultArr, resultStart + countMiddle, resultArr, resultStart, countLow); // Medium high result = Low(HighA * HighB) + High(LowA * LowB) + // High(HighA * HighB) c3 += AddUnevenSize( resultArr, resultStart + countMiddle, resultArr, resultStart + countMiddle, countLow, resultArr, resultStart + countMiddle + countLow, countLow - 2); if (offset2For1 == offset2For2) { // If high parts of both words were greater // than their low parts // or if low parts of both words were greater // than their high parts // Medium low/Medium high result = Medium low/Medium high result // - Low(Temp) c3 -= SubtractInternal( resultArr, resultStart + countLow, resultArr, resultStart + countLow, tempArr, tempStart + shorterOffset, countLow << 1); } else { // Medium low/Medium high result = Medium low/Medium high result // + Low(Temp) c3 += AddInternal( resultArr, resultStart + countLow, resultArr, resultStart + countLow, tempArr, tempStart + shorterOffset, countLow << 1); } // Add carry c3 += Increment( resultArr, resultStart + countMiddle, countLow, (short)c2); if (c3 != 0) { Increment( resultArr, resultStart + countMiddle + countLow, countLow - 2, (short)c3); } } } } private static void SchoolbookMultiply( short[] resultArr, int resultStart, short[] words1, int words1Start, int words1Count, short[] words2, int words2Start, int words2Count) { int cstart, carry, valueBint; if (words1Count < words2Count) { // words1 is shorter than words2, so put words2 on top carry = 0; valueBint = ((int)words1[words1Start]) & 0xffff; for (int j = 0; j < words2Count; ++j) { int p; p = ((((int)words2[words2Start + j]) & 0xffff) * valueBint); p = (p + (((int)carry) & 0xffff)); resultArr[resultStart + j] = ((short)p); carry = (p >> 16) & 0xffff; } resultArr[resultStart + words2Count] = ((short)carry); for (int i = 1; i < words1Count; ++i) { cstart = resultStart + i; carry = 0; valueBint = ((int)words1[words1Start + i]) & 0xffff; for (int j = 0; j < words2Count; ++j) { int p; p = ((((int)words2[words2Start + j]) & 0xffff) * valueBint); p = (p + (((int)carry) & 0xffff)); p = (p + (((int)resultArr[cstart + j]) & 0xffff)); resultArr[cstart + j] = ((short)p); carry = (p >> 16) & 0xffff; } resultArr[cstart + words2Count] = ((short)carry); } } else { // words2 is shorter or the same length as words1 carry = 0; valueBint = ((int)words2[words2Start]) & 0xffff; for (int j = 0; j < words1Count; ++j) { int p; p = ((((int)words1[words1Start + j]) & 0xffff) * valueBint); p = (p + (((int)carry) & 0xffff)); resultArr[resultStart + j] = ((short)p); carry = (p >> 16) & 0xffff; } resultArr[resultStart + words1Count] = ((short)carry); for (int i = 1; i < words2Count; ++i) { cstart = resultStart + i; carry = 0; valueBint = ((int)words2[words2Start + i]) & 0xffff; for (int j = 0; j < words1Count; ++j) { int p; p = ((((int)words1[words1Start + j]) & 0xffff) * valueBint); p = (p + (((int)carry) & 0xffff)); p = (p + (((int)resultArr[cstart + j]) & 0xffff)); resultArr[cstart + j] = ((short)p); carry = (p >> 16) & 0xffff; } resultArr[cstart + words1Count] = ((short)carry); } } } private static void SchoolbookSquare( short[] resultArr, int resultStart, short[] words1, int words1Start, int words1Count) { // Method assumes that resultArr was already zeroed, // if resultArr is the same as words1 int cstart; for (int i = 0; i < words1Count; ++i) { cstart = resultStart + i; { short carry = 0; int valueBint = ((int)words1[words1Start + i]) & 0xffff; for (int j = 0; j < words1Count; ++j) { int p; p = (((int)words1[words1Start + j]) & 0xffff) * valueBint; p += ((int)carry) & 0xffff; if (i != 0) { p += ((int)resultArr[cstart + j]) & 0xffff; } resultArr[cstart + j] = (short)p; carry = (short)(p >> 16); } resultArr[cstart + words1Count] = carry; } } } private static short ShiftWordsLeftByBits( short[] r, int rstart, int n, int shiftBits) { int u; int carry = 0; if (shiftBits != 0) { int sb16 = 16 - shiftBits; int rs = rstart; for (int i = 0; i < n; ++i, ++rs) { u = r[rs]; r[rs] = ((short)((u << shiftBits) | carry)); carry = (u & 0xffff) >> sb16; } } return (short)carry; } private static void ShiftWordsLeftByWords( short[] r, int rstart, int n, int shiftWords) { shiftWords = Math.min(shiftWords, n); if (shiftWords != 0) { for (int i = n - 1; i >= shiftWords; --i) { r[rstart + i] = r[rstart + i - shiftWords]; } java.util.Arrays.fill(r, rstart, (rstart)+(shiftWords), (short)0); } } private static short ShiftWordsRightByBits( short[] r, int rstart, int n, int shiftBits) { short u, carry = 0; { if (shiftBits != 0) { for (int i = n; i > 0; --i) { u = r[rstart + i - 1]; r[rstart + i - 1] = (short)((((((int)u) & 0xffff) >> (int)shiftBits) & 0xffff) | (((int)carry) & 0xffff)); carry = (short)((((int)u) & 0xffff) << (int)(16 - shiftBits)); } } return carry; } } private static short ShiftWordsRightByBitsSignExtend( short[] r, int rstart, int n, int shiftBits) { { short u, carry = (short)((int)0xffff << (int)(16 - shiftBits)); if (shiftBits != 0) { for (int i = n; i > 0; --i) { u = r[rstart + i - 1]; r[rstart + i - 1] = (short)(((((int)u) & 0xffff) >> (int)shiftBits) | (((int)carry) & 0xffff)); carry = (short)((((int)u) & 0xffff) << (int)(16 - shiftBits)); } } return carry; } } private static void ShiftWordsRightByWordsSignExtend( short[] r, int rstart, int n, int shiftWords) { shiftWords = Math.min(shiftWords, n); if (shiftWords != 0) { for (int i = 0; i + shiftWords < n; ++i) { r[rstart + i] = r[rstart + i + shiftWords]; } rstart += n - shiftWords; // Sign extend for (int i = 0; i < shiftWords; ++i) { r[rstart + i] = ((short)0xffff); } } } private static short[] ShortenArray(short[] reg, int wordCount) { if (reg.length > 32) { int newLength = wordCount; if (newLength < reg.length && (reg.length - newLength) >= 16) { // Reallocate the array if the desired length // is much smaller than the current length short[] newreg = new short[newLength]; System.arraycopy(reg, 0, newreg, 0, Math.min(newLength, reg.length)); reg = newreg; } } return reg; } private static int SubtractWords1IsOneBigger( short[] c, int cstart, short[] words1, int astart, short[] words2, int bstart, int words1Count) { // Assumes that words2's count is 1 less { int u; u = 0; int cm1 = words1Count - 1; for (int i = 0; i < cm1; i += 1) { u = (((int)words1[astart]) & 0xffff) - (((int)words2[bstart]) & 0xffff) - (int)((u >> 31) & 1); c[cstart++] = (short)u; ++astart; ++bstart; } u = (((int)words1[astart]) & 0xffff) - (int)((u >> 31) & 1); c[cstart++] = (short)u; return (int)((u >> 31) & 1); } } private static int SubtractWords2IsOneBigger( short[] c, int cstart, short[] words1, int astart, short[] words2, int bstart, int words2Count) { // Assumes that words1's count is 1 less int u; u = 0; int cm1 = words2Count - 1; for (int i = 0; i < cm1; i += 1) { u = ((((int)words1[astart]) & 0xffff) - (((int)words2[bstart]) & 0xffff) - (int)((u >> 31) & 1)); c[cstart++] = ((short)u); ++astart; ++bstart; } u = 0 - ((((int)words2[bstart]) & 0xffff) - (int)((u >> 31) & 1)); c[cstart++] = ((short)u); return (int)((u >> 31) & 1); } private static int SubtractInternal( short[] c, int cstart, short[] words1, int astart, short[] words2, int bstart, int n) { int u = 0; boolean odd = (n & 1) != 0; if (odd) { --n; } int mask = 0xffff; for (int i = 0; i < n; i += 2) { int wb0 = words2[bstart] & mask; int wb1 = words2[bstart + 1] & mask; int wa0 = words1[astart] & mask; int wa1 = words1[astart + 1] & mask; u = (wa0 - wb0 - (int)((u >> 31) & 1)); c[cstart++] = ((short)u); u = (wa1 - wb1 - (int)((u >> 31) & 1)); c[cstart++] = ((short)u); astart += 2; bstart += 2; } if (odd) { u = ((((int)words1[astart]) & mask) - (((int)words2[bstart]) & mask) - (int)((u >> 31) & 1)); c[cstart++] = ((short)u); ++astart; ++bstart; } return (int)((u >> 31) & 1); } private static void TwosComplement(short[] words1, int words1Start, int n) { Decrement(words1, words1Start, n, (short)1); for (int i = 0; i < n; ++i) { words1[words1Start + i] = ((short)(~words1[words1Start + i])); } } private int ByteCount() { int wc = this.wordCount; if (wc == 0) { return 0; } short s = this.words[wc - 1]; wc = (wc - 1) << 1; return (s == 0) ? wc : (((s >> 8) == 0) ? wc + 1 : wc + 2); } private boolean HasSmallValue() { int c = (int)this.wordCount; if (c > 4) { return false; } if (c == 4 && (this.words[3] & 0x8000) != 0) { return this.negative && this.words[3] == ((short)0x8000) && this.words[2] == 0 && this.words[1] == 0 && this.words[0] == 0; } return true; } private int PositiveCompare(EInteger t) { int size = this.wordCount, tempSize = t.wordCount; return ( size == tempSize) ? Compare( this.words, 0, t.words, 0, (int)size) : (size > tempSize ? 1 : -1); } private String SmallValueToString() { long value = this.ToInt64Unchecked(); if (value == Long.MIN_VALUE) { return "-9223372036854775808"; } if (value == (long)Integer.MIN_VALUE) { return "-2147483648"; } boolean neg = value < 0; int count = 0; char[] chars; int intvalue = ((int)value); if ((long)intvalue == value) { chars = new char[12]; count = 11; if (neg) { intvalue = -intvalue; } while (intvalue > 43698) { int intdivvalue = intvalue / 10; char digit = Digits.charAt((int)(intvalue - (intdivvalue * 10))); chars[count--] = digit; intvalue = intdivvalue; } while (intvalue > 9) { int intdivvalue = (intvalue * 26215) >> 18; char digit = Digits.charAt((int)(intvalue - (intdivvalue * 10))); chars[count--] = digit; intvalue = intdivvalue; } if (intvalue != 0) { chars[count--] = Digits.charAt(intvalue); } if (neg) { chars[count] = '-'; } else { ++count; } return new String(chars, count, 12 - count); } else { chars = new char[24]; count = 23; if (neg) { value = -value; } while (value > 9) { long divvalue = value / 10; char digit = Digits.charAt((int)(value - (divvalue * 10))); chars[count--] = digit; value = divvalue; } if (value != 0) { chars[count--] = Digits.charAt((int)value); } if (neg) { chars[count] = '-'; } else { ++count; } return new String(chars, count, 24 - count); } } private EInteger[] SqrtRemInternal(boolean useRem) { if (this.signum() <= 0) { return new EInteger[] { EInteger.FromInt32(0), EInteger.FromInt32(0) }; } if (this.equals(EInteger.FromInt32(1))) { return new EInteger[] { EInteger.FromInt32(1), EInteger.FromInt32(0) }; } EInteger bigintX; EInteger bigintY; EInteger thisValue = this; int powerBits = (thisValue.GetUnsignedBitLength() + 1) / 2; if (thisValue.CanFitInInt32()) { int smallValue = thisValue.ToInt32Checked(); // No need to check for ValueZero; already done above int smallintX = 0; int smallintY = 1 << powerBits; do { smallintX = smallintY; smallintY = smallValue / smallintX; smallintY += smallintX; smallintY >>= 1; } while (smallintY < smallintX); if (!useRem) { return new EInteger[] { EInteger.FromInt32(smallintX), null }; } smallintY = smallintX * smallintX; smallintY = smallValue - smallintY; return new EInteger[] { EInteger.FromInt32(smallintX), EInteger.FromInt32(smallintY) }; } if (this.wordCount >= 4) { int wordsPerPart = (this.wordCount + 3) >> 2; int bitsPerPart = wordsPerPart * 16; int totalBits = bitsPerPart * 4; int bitLength = this.GetUnsignedBitLength(); boolean bitLengthEven = (bitLength & 1) == 0; bigintX = this; int shift = 0; if (bitLength < totalBits - 1) { int targetLength = bitLengthEven ? totalBits : (totalBits - 1); shift = targetLength - bitLength; bigintX = bigintX.ShiftLeft(shift); } // DebugUtility.Log("this=" + (this.ToRadixString(16))); // DebugUtility.Log("bigx=" + (bigintX.ToRadixString(16))); short[] ww = bigintX.words; short[] w1 = new short[wordsPerPart]; short[] w2 = new short[wordsPerPart]; short[] w3 = new short[wordsPerPart * 2]; System.arraycopy(ww, 0, w1, 0, wordsPerPart); System.arraycopy(ww, wordsPerPart, w2, 0, wordsPerPart); System.arraycopy(ww, wordsPerPart * 2, w3, 0, wordsPerPart * 2); EInteger e1 = new EInteger(CountWords(w1), w1, false); EInteger e2 = new EInteger(CountWords(w2), w2, false); EInteger e3 = new EInteger(CountWords(w3), w3, false); EInteger[] srem = e3.SqrtRemInternal(true); // DebugUtility.Log("sqrt0({0})[depth={3}] = {1},{2}" // , e3, srem[0], srem[1], 0); // DebugUtility.Log("sqrt1({0})[depth={3}] = {1},{2}" // , e3, srem2.get(0), srem2.get(1), 0); // if (!srem[0].equals(srem2.get(0)) || !srem[1].equals(srem2.get(1))) { // throw new IllegalStateException(this.toString()); // } EInteger[] qrem = srem[1].ShiftLeft(bitsPerPart).Add(e2).DivRem( srem[0].ShiftLeft(1)); EInteger sqroot = srem[0].ShiftLeft(bitsPerPart).Add(qrem[0]); EInteger sqrem = qrem[1].ShiftLeft(bitsPerPart).Add(e1).Subtract( qrem[0].Multiply(qrem[0])); // DebugUtility.Log("sqrem=" + sqrem + ",sqroot=" + sqroot); if (sqrem.signum() < 0) { if (useRem) { sqrem = sqrem.Add(sqroot.ShiftLeft(1)).Subtract(EInteger.FromInt32(1)); } sqroot = sqroot.Subtract(EInteger.FromInt32(1)); } /* DebugUtility.Log("sqrt({0}) = {1},{2},\n---shift={3},words={4},wpp={5},bxwords={6}", this, sqroot, sqrem, shift, this.wordCount, wordsPerPart, bigintX.wordCount); if (useRem) { DebugUtility.Log("srshHalf=" + (sqrem.ShiftRight(shift>>1))); DebugUtility.Log("srshFull=" + (sqrem.ShiftRight(shift))); } */ EInteger[] retarr = new EInteger[2]; retarr[0] = sqroot.ShiftRight(shift >> 1); if (useRem) { if (shift == 0) { retarr[1] = sqrem; } else { retarr[1] = this.Subtract(retarr[0].Multiply(retarr[0])); } } return retarr; } bigintX = EInteger.FromInt32(0); bigintY = EInteger.FromInt32(1).ShiftLeft(powerBits); do { bigintX = bigintY; // DebugUtility.Log("" + thisValue + " " + bigintX); bigintY = thisValue.Divide(bigintX); bigintY = bigintY.Add(bigintX); bigintY = bigintY.ShiftRight(1); } while (bigintY != null && bigintY.compareTo(bigintX) < 0); if (!useRem) { return new EInteger[] { bigintX, null }; } bigintY = bigintX.Multiply(bigintX); bigintY = thisValue.Subtract(bigintY); return new EInteger[] { bigintX, bigintY }; } // Begin integer conversions /** * Converts this number's value to a byte (from 0 to 255) if it can fit in a * byte (from 0 to 255). * @return This number's value as a byte (from 0 to 255). * @throws java.lang.ArithmeticException This value is less than 0 or greater than * 255. */ public byte ToByteChecked() { int val = this.ToInt32Checked(); if (val < 0 || val > 255) { throw new ArithmeticException("This Object's value is out of range"); } return (byte)(val & 0xff); } /** * Converts this number to a byte (from 0 to 255), returning the * least-significant bits of this number's two's-complement form. * @return This number, converted to a byte (from 0 to 255). */ public byte ToByteUnchecked() { int val = this.ToInt32Unchecked(); return (byte)(val & 0xff); } /** * Converts a byte (from 0 to 255) to an arbitrary-precision integer. * @param inputByte The number to convert as a byte (from 0 to 255). * @return This number's value as an arbitrary-precision integer. */ public static EInteger FromByte(byte inputByte) { int val = ((int)inputByte) & 0xff; return FromInt32(val); } /** * Converts this number's value to a 16-bit signed integer if it can fit in a * 16-bit signed integer. * @return This number's value as a 16-bit signed integer. * @throws java.lang.ArithmeticException This value is less than -32768 or greater * than 32767. */ public short ToInt16Checked() { int val = this.ToInt32Checked(); if (val < -32768 || val > 32767) { throw new ArithmeticException("This Object's value is out of range"); } return (short)(val & 0xffff); } /** * Converts this number to a 16-bit signed integer, returning the * least-significant bits of this number's two's-complement form. * @return This number, converted to a 16-bit signed integer. */ public short ToInt16Unchecked() { int val = this.ToInt32Unchecked(); return (short)(val & 0xffff); } /** * Converts a 16-bit signed integer to an arbitrary-precision integer. * @param inputInt16 The number to convert as a 16-bit signed integer. * @return This number's value as an arbitrary-precision integer. */ public static EInteger FromInt16(short inputInt16) { int val = (int)inputInt16; return FromInt32(val); } // End integer conversions }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy