/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package java.math; /** * Static library that provides {@link BigInteger} base conversion from/to any * integer represented in an {@link java.lang.String} Object. */ class Conversion { /** Just to denote that this class can't be instantiated */ private Conversion() {} /** * Holds the maximal exponent for each radix, so that radix<sup>digitFitInInt[radix]</sup> * fit in an {@code int} (32 bits). */ static final int[] digitFitInInt = { -1, -1, 31, 19, 15, 13, 11, 11, 10, 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5 }; /** * bigRadices values are precomputed maximal powers of radices (integer * numbers from 2 to 36) that fit into unsigned int (32 bits). bigRadices[0] = * 2 ^ 31, bigRadices[8] = 10 ^ 9, etc. */ static final int[] bigRadices = { -2147483648, 1162261467, 1073741824, 1220703125, 362797056, 1977326743, 1073741824, 387420489, 1000000000, 214358881, 429981696, 815730721, 1475789056, 170859375, 268435456, 410338673, 612220032, 893871739, 1280000000, 1801088541, 113379904, 148035889, 191102976, 244140625, 308915776, 387420489, 481890304, 594823321, 729000000, 887503681, 1073741824, 1291467969, 1544804416, 1838265625, 60466176 }; /** @see BigInteger#toString(int) */ static String bigInteger2String(BigInteger val, int radix) { val.prepareJavaRepresentation(); int sign = val.sign; int numberLength = val.numberLength; int[] digits = val.digits; if (sign == 0) { return "0"; } if (numberLength == 1) { int highDigit = digits[numberLength - 1]; long v = highDigit & 0xFFFFFFFFL; if (sign < 0) { v = -v; } return Long.toString(v, radix); } if ((radix == 10) || (radix < Character.MIN_RADIX) || (radix > Character.MAX_RADIX)) { return val.toString(); } double bitsForRadixDigit; bitsForRadixDigit = Math.log(radix) / Math.log(2); int resLengthInChars = (int) (val.abs().bitLength() / bitsForRadixDigit + ((sign < 0) ? 1 : 0)) + 1; char[] result = new char[resLengthInChars]; int currentChar = resLengthInChars; int resDigit; if (radix != 16) { int[] temp = new int[numberLength]; System.arraycopy(digits, 0, temp, 0, numberLength); int tempLen = numberLength; int charsPerInt = digitFitInInt[radix]; int i; // get the maximal power of radix that fits in int int bigRadix = bigRadices[radix - 2]; while (true) { // divide the array of digits by bigRadix and convert remainders // to characters collecting them in the char array resDigit = Division.divideArrayByInt(temp, temp, tempLen, bigRadix); int previous = currentChar; do { result[--currentChar] = Character.forDigit( resDigit % radix, radix); } while (((resDigit /= radix) != 0) && (currentChar != 0)); int delta = charsPerInt - previous + currentChar; for (i = 0; i < delta && currentChar > 0; i++) { result[--currentChar] = '0'; } for (i = tempLen - 1; (i > 0) && (temp[i] == 0); i--) { ; } tempLen = i + 1; if ((tempLen == 1) && (temp[0] == 0)) { // the quotient is 0 break; } } } else { // radix == 16 for (int i = 0; i < numberLength; i++) { for (int j = 0; (j < 8) && (currentChar > 0); j++) { resDigit = digits[i] >> (j << 2) & 0xf; result[--currentChar] = Character.forDigit(resDigit, 16); } } } while (result[currentChar] == '0') { currentChar++; } if (sign == -1) { result[--currentChar] = '-'; } return new String(result, currentChar, resLengthInChars - currentChar); } /** * Builds the correspondent {@code String} representation of {@code val} * being scaled by {@code scale}. * * @see BigInteger#toString() * @see BigDecimal#toString() */ static String toDecimalScaledString(BigInteger val, int scale) { val.prepareJavaRepresentation(); int sign = val.sign; int numberLength = val.numberLength; int[] digits = val.digits; int resLengthInChars; int currentChar; char[] result; if (sign == 0) { switch (scale) { case 0: return "0"; case 1: return "0.0"; case 2: return "0.00"; case 3: return "0.000"; case 4: return "0.0000"; case 5: return "0.00000"; case 6: return "0.000000"; default: StringBuilder result1 = new StringBuilder(); if (scale < 0) { result1.append("0E+"); } else { result1.append("0E"); } result1.append(-scale); return result1.toString(); } } // one 32-bit unsigned value may contains 10 decimal digits resLengthInChars = numberLength * 10 + 1 + 7; // Explanation why +1+7: // +1 - one char for sign if needed. // +7 - For "special case 2" (see below) we have 7 free chars for // inserting necessary scaled digits. result = new char[resLengthInChars + 1]; // allocated [resLengthInChars+1] characters. // a free latest character may be used for "special case 1" (see // below) currentChar = resLengthInChars; if (numberLength == 1) { int highDigit = digits[0]; if (highDigit < 0) { long v = highDigit & 0xFFFFFFFFL; do { long prev = v; v /= 10; result[--currentChar] = (char) (0x0030 + ((int) (prev - v * 10))); } while (v != 0); } else { int v = highDigit; do { int prev = v; v /= 10; result[--currentChar] = (char) (0x0030 + (prev - v * 10)); } while (v != 0); } } else { int[] temp = new int[numberLength]; int tempLen = numberLength; System.arraycopy(digits, 0, temp, 0, tempLen); BIG_LOOP: while (true) { // divide the array of digits by bigRadix and convert // remainders // to characters collecting them in the char array long result11 = 0; for (int i1 = tempLen - 1; i1 >= 0; i1--) { long temp1 = (result11 << 32) + (temp[i1] & 0xFFFFFFFFL); long res = divideLongByBillion(temp1); temp[i1] = (int) res; result11 = (int) (res >> 32); } int resDigit = (int) result11; int previous = currentChar; do { result[--currentChar] = (char) (0x0030 + (resDigit % 10)); } while (((resDigit /= 10) != 0) && (currentChar != 0)); int delta = 9 - previous + currentChar; for (int i = 0; (i < delta) && (currentChar > 0); i++) { result[--currentChar] = '0'; } int j = tempLen - 1; for (; temp[j] == 0; j--) { if (j == 0) { // means temp[0] == 0 break BIG_LOOP; } } tempLen = j + 1; } while (result[currentChar] == '0') { currentChar++; } } boolean negNumber = (sign < 0); int exponent = resLengthInChars - currentChar - scale - 1; if (scale == 0) { if (negNumber) { result[--currentChar] = '-'; } return new String(result, currentChar, resLengthInChars - currentChar); } if ((scale > 0) && (exponent >= -6)) { if (exponent >= 0) { // special case 1 int insertPoint = currentChar + exponent; for (int j = resLengthInChars - 1; j >= insertPoint; j--) { result[j + 1] = result[j]; } result[++insertPoint] = '.'; if (negNumber) { result[--currentChar] = '-'; } return new String(result, currentChar, resLengthInChars - currentChar + 1); } // special case 2 for (int j = 2; j < -exponent + 1; j++) { result[--currentChar] = '0'; } result[--currentChar] = '.'; result[--currentChar] = '0'; if (negNumber) { result[--currentChar] = '-'; } return new String(result, currentChar, resLengthInChars - currentChar); } int startPoint = currentChar + 1; int endPoint = resLengthInChars; StringBuilder result1 = new StringBuilder(16 + endPoint - startPoint); if (negNumber) { result1.append('-'); } if (endPoint - startPoint >= 1) { result1.append(result[currentChar]); result1.append('.'); result1.append(result, currentChar + 1, resLengthInChars - currentChar - 1); } else { result1.append(result, currentChar, resLengthInChars - currentChar); } result1.append('E'); if (exponent > 0) { result1.append('+'); } result1.append(Integer.toString(exponent)); return result1.toString(); } /* can process only 32-bit numbers */ static String toDecimalScaledString(long value, int scale) { int resLengthInChars; int currentChar; char[] result; boolean negNumber = value < 0; if(negNumber) { value = -value; } if (value == 0) { switch (scale) { case 0: return "0"; case 1: return "0.0"; case 2: return "0.00"; case 3: return "0.000"; case 4: return "0.0000"; case 5: return "0.00000"; case 6: return "0.000000"; default: StringBuilder result1 = new StringBuilder(); if (scale < 0) { result1.append("0E+"); } else { result1.append("0E"); } result1.append( (scale == Integer.MIN_VALUE) ? "2147483648" : Integer.toString(-scale)); return result1.toString(); } } // one 32-bit unsigned value may contains 10 decimal digits resLengthInChars = 18; // Explanation why +1+7: // +1 - one char for sign if needed. // +7 - For "special case 2" (see below) we have 7 free chars for // inserting necessary scaled digits. result = new char[resLengthInChars+1]; // Allocated [resLengthInChars+1] characters. // a free latest character may be used for "special case 1" (see below) currentChar = resLengthInChars; long v = value; do { long prev = v; v /= 10; result[--currentChar] = (char) (0x0030 + (prev - v * 10)); } while (v != 0); long exponent = (long)resLengthInChars - (long)currentChar - scale - 1L; if (scale == 0) { if (negNumber) { result[--currentChar] = '-'; } return new String(result, currentChar, resLengthInChars - currentChar); } if (scale > 0 && exponent >= -6) { if (exponent >= 0) { // special case 1 int insertPoint = currentChar + (int) exponent ; for (int j=resLengthInChars-1; j>=insertPoint; j--) { result[j+1] = result[j]; } result[++insertPoint]='.'; if (negNumber) { result[--currentChar] = '-'; } return new String(result, currentChar, resLengthInChars - currentChar + 1); } // special case 2 for (int j = 2; j < -exponent + 1; j++) { result[--currentChar] = '0'; } result[--currentChar] = '.'; result[--currentChar] = '0'; if (negNumber) { result[--currentChar] = '-'; } return new String(result, currentChar, resLengthInChars - currentChar); } int startPoint = currentChar + 1; int endPoint = resLengthInChars; StringBuilder result1 = new StringBuilder(16 + endPoint - startPoint); if (negNumber) { result1.append('-'); } if (endPoint - startPoint >= 1) { result1.append(result[currentChar]); result1.append('.'); result1.append(result,currentChar+1,resLengthInChars - currentChar-1); } else { result1.append(result,currentChar,resLengthInChars - currentChar); } result1.append('E'); if (exponent > 0) { result1.append('+'); } result1.append(Long.toString(exponent)); return result1.toString(); } static long divideLongByBillion(long a) { long quot; long rem; if (a >= 0) { long bLong = 1000000000L; quot = (a / bLong); rem = (a % bLong); } else { /* * Make the dividend positive shifting it right by 1 bit then get * the quotient an remainder and correct them properly */ long aPos = a >>> 1; long bPos = 1000000000L >>> 1; quot = aPos / bPos; rem = aPos % bPos; // double the remainder and add 1 if 'a' is odd rem = (rem << 1) + (a & 1); } return ((rem << 32) | (quot & 0xFFFFFFFFL)); } /** @see BigInteger#doubleValue() */ static double bigInteger2Double(BigInteger val) { val.prepareJavaRepresentation(); // val.bitLength() < 64 if ((val.numberLength < 2) || ((val.numberLength == 2) && (val.digits[1] > 0))) { return val.longValue(); } // val.bitLength() >= 33 * 32 > 1024 if (val.numberLength > 32) { return ((val.sign > 0) ? Double.POSITIVE_INFINITY : Double.NEGATIVE_INFINITY); } int bitLen = val.abs().bitLength(); long exponent = bitLen - 1; int delta = bitLen - 54; // We need 54 top bits from this, the 53th bit is always 1 in lVal. long lVal = val.abs().shiftRight(delta).longValue(); /* * Take 53 bits from lVal to mantissa. The least significant bit is * needed for rounding. */ long mantissa = lVal & 0x1FFFFFFFFFFFFFL; if (exponent == 1023) { if (mantissa == 0X1FFFFFFFFFFFFFL) { return ((val.sign > 0) ? Double.POSITIVE_INFINITY : Double.NEGATIVE_INFINITY); } if (mantissa == 0x1FFFFFFFFFFFFEL) { return ((val.sign > 0) ? Double.MAX_VALUE : -Double.MAX_VALUE); } } // Round the mantissa if (((mantissa & 1) == 1) && (((mantissa & 2) == 2) || BitLevel.nonZeroDroppedBits(delta, val.digits))) { mantissa += 2; } mantissa >>= 1; // drop the rounding bit long resSign = (val.sign < 0) ? 0x8000000000000000L : 0; exponent = ((1023 + exponent) << 52) & 0x7FF0000000000000L; long result = resSign | exponent | mantissa; return Double.longBitsToDouble(result); } }