2020 * checks if each side of the operator is the same instance).</p>
2121 */
2222 public final class BigInteger implements Comparable <BigInteger > {
23-
2423 private static int CountWords (short [] array , int n ) {
2524 while (n != 0 && array [n - 1 ] == 0 ) {
2625 --n ;
@@ -2108,8 +2107,8 @@ private static short Divide32By16(
21082107 }
21092108 }
21102109 }
2111- return returnRemainder ? ((short )(((int )dividendHigh ) &
2112- 0xffff )) : ((short )(((int )dividendLow ) & 0xffff ));
2110+ return returnRemainder ? ((short )(((int )dividendHigh ) &
2111+ 0xffff )) : ((short )(((int )dividendLow ) & 0xffff ));
21132112 }
21142113
21152114 private static short DivideUnsigned (int x , short y ) {
@@ -2232,8 +2231,8 @@ private static void AtomicMultiplyOpt(
22322231 int a0b0high = (valueA0B0 >> 16 ) & 0xffff ;
22332232 int valueA1B1 = valueA1 * valueB1 ;
22342233 int tempInt ;
2235- tempInt = a0b0high + (((int )valueA0B0 ) & 0xffff ) + (((int )d ) &
2236- 0xffff ) + (((int )valueA1B1 ) & 0xffff );
2234+ tempInt = a0b0high + (((int )valueA0B0 ) & 0xffff ) + (((int )d ) &
2235+ 0xffff ) + (((int )valueA1B1 ) & 0xffff );
22372236 c [csi + 1 ] = (short )(((int )tempInt ) & 0xffff );
22382237
22392238 tempInt = valueA1B1 + (((int )(tempInt >> 16 )) & 0xffff ) +
@@ -2262,8 +2261,8 @@ private static void AtomicMultiplyOpt(
22622261
22632262 int valueA1B1 = valueA1 * valueB1 ;
22642263 int tempInt ;
2265- tempInt = a0b0high + (((int )valueA0B0 ) & 0xffff ) + (((int )d ) &
2266- 0xffff ) + (((int )valueA1B1 ) & 0xffff );
2264+ tempInt = a0b0high + (((int )valueA0B0 ) & 0xffff ) + (((int )d ) &
2265+ 0xffff ) + (((int )valueA1B1 ) & 0xffff );
22672266 c [csi + 1 ] = (short )(((int )tempInt ) & 0xffff );
22682267
22692268 tempInt = valueA1B1 + (((int )(tempInt >> 16 )) & 0xffff ) +
@@ -3668,13 +3667,31 @@ public static BigInteger fromString(String str) {
36683667 if (str == null ) {
36693668 throw new NullPointerException ("str" );
36703669 }
3671- return fromSubstring (str , 0 , str .length ());
3670+ return fromRadixSubstring (str , 10 , 0 , str .length ());
36723671 }
36733672
3674- private static final int MaxSafeInt = 214748363 ;
3673+ /**
3674+ * Converts a string to an arbitrary-precision integer in a given radix.
3675+ * @param str A string containing only digits, except that it may start with a
3676+ * minus sign.
3677+ * @param radix A base from 2 to 36. The possible digits start from 0 to 9,
3678+ * then from A to Z in base 36, and the possible digits start from 0 to
3679+ * 9, then from A to F in base 16.
3680+ * @return A BigInteger object with the same value as given in the string.
3681+ * @throws NullPointerException The parameter {@code str} is null.
3682+ * @throws NumberFormatException The parameter {@code str} is in an invalid format.
3683+ */
3684+ public static BigInteger fromRadixString (String str , int radix ) {
3685+ if (str == null ) {
3686+ throw new NullPointerException ("str" );
3687+ }
3688+ return fromRadixSubstring (str , radix , 0 , str .length ());
3689+ }
36753690
36763691 /**
3677- * Converts a portion of a string to an arbitrary-precision integer.
3692+ * Converts a portion of a string to an arbitrary-precision integer. The string
3693+ * portion can begin with a minus sign ('-') to indicate that it's
3694+ * negative.
36783695 * @param str A string object.
36793696 * @param index The index of the string that starts the string portion.
36803697 * @param endIndex The index of the string that ends the string portion. The
@@ -3694,6 +3711,65 @@ public static BigInteger fromSubstring(
36943711 if (str == null ) {
36953712 throw new NullPointerException ("str" );
36963713 }
3714+ return fromRadixSubstring (str , 10 , index , endIndex );
3715+ }
3716+
3717+ private static int [] valueMaxSafeInts = { 1073741823 , 715827881 ,
3718+ 536870911 , 429496728 , 357913940 , 306783377 , 268435455 , 238609293 ,
3719+ 214748363 , 195225785 , 178956969 , 165191048 , 153391688 , 143165575 ,
3720+ 134217727 , 126322566 , 119304646 , 113025454 , 107374181 , 102261125 ,
3721+ 97612892 , 93368853 , 89478484 , 85899344 , 82595523 , 79536430 , 76695843 ,
3722+ 74051159 , 71582787 , 69273665 , 67108863 , 65075261 , 63161282 , 61356674 ,
3723+ 59652322 };
3724+
3725+ private static int [] valueCharToDigit = { 36 , 36 , 36 , 36 , 36 , 36 , 36 ,
3726+ 36 ,
3727+ 36 , 36 , 36 , 36 , 36 , 36 , 36 , 36 ,
3728+ 36 , 36 , 36 , 36 , 36 , 36 , 36 , 36 ,
3729+ 36 , 36 , 36 , 36 , 36 , 36 , 36 , 36 ,
3730+ 36 , 36 , 36 , 36 , 36 , 36 , 36 , 36 ,
3731+ 36 , 36 , 36 , 36 , 36 , 36 , 36 , 36 ,
3732+ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 36 , 36 , 36 , 36 , 36 , 36 ,
3733+ 36 , 10 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 ,
3734+ 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 36 , 36 , 36 , 36 ,
3735+ 36 , 10 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 ,
3736+ 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 36 , 36 , 36 , 36 };
3737+
3738+ /**
3739+ * Converts a portion of a string to an arbitrary-precision integer in a given
3740+ * radix. The string portion can begin with a minus sign ('-') to
3741+ * indicate that it's negative.
3742+ * @param str A string object.
3743+ * @param radix A base from 2 to 36. The possible digits start from 0 to 9,
3744+ * then from A to Z in base 36, and the possible digits start from 0 to
3745+ * 9, then from A to F in base 16.
3746+ * @param index The index of the string that starts the string portion.
3747+ * @param endIndex The index of the string that ends the string portion. The
3748+ * length will be index + endIndex - 1.
3749+ * @return A BigInteger object with the same value as given in the string
3750+ * portion.
3751+ * @throws NullPointerException The parameter {@code str} is null.
3752+ * @throws IllegalArgumentException The parameter {@code index} is less than 0, {@code
3753+ * endIndex} is less than 0, or either is greater than the string's
3754+ * length, or {@code endIndex} is less than {@code index} .
3755+ * @throws NumberFormatException The string portion is empty or in an invalid format.
3756+ */
3757+ public static BigInteger fromRadixSubstring (
3758+ String str ,
3759+ int radix ,
3760+ int index ,
3761+ int endIndex ) {
3762+ if (str == null ) {
3763+ throw new NullPointerException ("str" );
3764+ }
3765+ if (radix < 2 ) {
3766+ throw new IllegalArgumentException ("radix (" + radix +
3767+ ") is less than 2" );
3768+ }
3769+ if (radix > 36 ) {
3770+ throw new IllegalArgumentException ("radix (" + radix +
3771+ ") is more than 36" );
3772+ }
36973773 if (index < 0 ) {
36983774 throw new IllegalArgumentException ("index (" + index + ") is less than " +
36993775 "0" );
@@ -3703,8 +3779,8 @@ public static BigInteger fromSubstring(
37033779 str .length ());
37043780 }
37053781 if (endIndex < 0 ) {
3706- throw new IllegalArgumentException ("endIndex (" + endIndex +
3707- ") is less than " + "0" );
3782+ throw new IllegalArgumentException ("endIndex (" + endIndex +
3783+ ") is less than " + "0" );
37083784 }
37093785 if (endIndex > str .length ()) {
37103786 throw new IllegalArgumentException ("endIndex (" + endIndex +
@@ -3718,62 +3794,121 @@ public static BigInteger fromSubstring(
37183794 throw new NumberFormatException ("No digits" );
37193795 }
37203796 boolean negative = false ;
3721- if (str .charAt (0 ) == '-' ) {
3797+ if (str .charAt (index ) == '-' ) {
37223798 ++index ;
3799+ if (index == endIndex ) {
3800+ throw new NumberFormatException ("No digits" );
3801+ }
37233802 negative = true ;
37243803 }
3725- short [] bigint = new short [4 ];
3726- boolean haveDigits = false ;
3727- boolean haveSmallInt = true ;
3728- int smallInt = 0 ;
3729- for (int i = index ; i < endIndex ; ++i ) {
3730- char c = str .charAt (i );
3731- if (c < '0' || c > '9' ) {
3732- throw new NumberFormatException ("Illegal character found" );
3804+ // Skip leading zeros
3805+ for (; index < endIndex ; ++index ) {
3806+ char c = str .charAt (index );
3807+ if (c != 0x30 ) {
3808+ break ;
37333809 }
3734- haveDigits = true ;
3735- int digit = (int )(c - '0' );
3736- if (haveSmallInt && smallInt < MaxSafeInt ) {
3737- smallInt *= 10 ;
3738- smallInt += digit ;
3739- } else {
3740- if (haveSmallInt ) {
3741- bigint [0 ] = ((short )(smallInt & 0xffff ));
3742- bigint [1 ] = ((short )((smallInt >> 16 ) & 0xffff ));
3743- haveSmallInt = false ;
3744- }
3745- // Multiply by 10
3746- short carry = 0 ;
3747- int n = bigint .length ;
3748- for (int j = 0 ; j < n ; ++j ) {
3749- int p ;
3750- {
3751- p = (((int )bigint [j ]) & 0xffff ) * 10 ;
3752- p += ((int )carry ) & 0xffff ;
3753- bigint [j ] = (short )p ;
3754- carry = (short )(p >> 16 );
3810+ }
3811+ int effectiveLength = endIndex - index ;
3812+ if (effectiveLength == 0 ) {
3813+ return BigInteger .ZERO ;
3814+ }
3815+ short [] bigint ;
3816+ if (radix == 16 ) {
3817+ // Special case for hexadecimal radix
3818+ int leftover = effectiveLength & 3 ;
3819+ int wordCount = effectiveLength >> 2 ;
3820+ if (leftover != 0 ) {
3821+ ++wordCount ;
3822+ }
3823+ bigint = new short [wordCount ];
3824+ int currentDigit = wordCount - 1 ;
3825+ // Get most significant digits if effective
3826+ // length is not divisible by 4
3827+ if (leftover != 0 ) {
3828+ int extraWord = 0 ;
3829+ for (int i = 0 ; i < leftover ; ++i ) {
3830+ extraWord <<= 4 ;
3831+ char c = str .charAt (index + i );
3832+ int digit = (c >= 0x80 ) ? 36 : valueCharToDigit [(int )c ];
3833+ if (digit >= 16 ) {
3834+ throw new NumberFormatException ("Illegal character found" );
37553835 }
3836+ extraWord |= digit ;
37563837 }
3757- if (carry != 0 ) {
3758- bigint = GrowForCarry (bigint , carry );
3838+ bigint [currentDigit ] = ((short )extraWord );
3839+ --currentDigit ;
3840+ index += leftover ;
3841+ }
3842+
3843+ while (index < endIndex ) {
3844+ char c = str .charAt (index + 3 );
3845+ int digit = (c >= 0x80 ) ? 36 : valueCharToDigit [(int )c ];
3846+ int word = digit ;
3847+ c = str .charAt (index + 2 );
3848+ digit = (c >= 0x80 ) ? 36 : valueCharToDigit [(int )c ];
3849+ word |= digit << 4 ;
3850+ c = str .charAt (index + 1 );
3851+ digit = (c >= 0x80 ) ? 36 : valueCharToDigit [(int )c ];
3852+ word |= digit << 8 ;
3853+ c = str .charAt (index );
3854+ digit = (c >= 0x80 ) ? 36 : valueCharToDigit [(int )c ];
3855+ word |= digit << 12 ;
3856+ index += 4 ;
3857+ bigint [currentDigit ] = ((short )word );
3858+ --currentDigit ;
3859+ }
3860+ } else {
3861+ bigint = new short [4 ];
3862+ boolean haveSmallInt = true ;
3863+ int maxSafeInt = valueMaxSafeInts [radix - 2 ];
3864+ int maxShortPlusOneMinusRadix = 65536 - radix ;
3865+ int smallInt = 0 ;
3866+ for (int i = index ; i < endIndex ; ++i ) {
3867+ char c = str .charAt (i );
3868+ int digit = (c >= 0x80 ) ? 36 : valueCharToDigit [(int )c ];
3869+ if (digit >= radix ) {
3870+ throw new NumberFormatException ("Illegal character found" );
37593871 }
3760- // Add the parsed digit
3761- if (digit != 0 ) {
3762- int d = bigint [0 ] & 0xffff ;
3763- if (d <= 65526 ) {
3764- bigint [0 ] = ((short )(d + digit ));
3765- } else if (Increment (bigint , 0 , bigint .length , (short )digit ) != 0 ) {
3766- bigint = GrowForCarry (bigint , (short )1 );
3872+ if (haveSmallInt && smallInt < maxSafeInt ) {
3873+ smallInt *= radix ;
3874+ smallInt += digit ;
3875+ } else {
3876+ if (haveSmallInt ) {
3877+ bigint [0 ] = ((short )(smallInt & 0xffff ));
3878+ bigint [1 ] = ((short )((smallInt >> 16 ) & 0xffff ));
3879+ haveSmallInt = false ;
3880+ }
3881+ // Multiply by the radix
3882+ short carry = 0 ;
3883+ int n = bigint .length ;
3884+ for (int j = 0 ; j < n ; ++j ) {
3885+ int p ;
3886+ {
3887+ p = (((int )bigint [j ]) & 0xffff ) * radix ;
3888+ p += ((int )carry ) & 0xffff ;
3889+ bigint [j ] = (short )p ;
3890+ carry = (short )(p >> 16 );
3891+ }
3892+ }
3893+ if (carry != 0 ) {
3894+ bigint = GrowForCarry (bigint , carry );
3895+ }
3896+ // Add the parsed digit
3897+ if (digit != 0 ) {
3898+ int d = bigint [0 ] & 0xffff ;
3899+ if (d <= maxShortPlusOneMinusRadix ) {
3900+ bigint [0 ] = ((short )(d + digit ));
3901+ } else if (Increment (bigint , 0 , bigint .length , (short )digit ) !=
3902+ 0 ) {
3903+ bigint = GrowForCarry (bigint , (short )1 );
3904+ }
37673905 }
37683906 }
37693907 }
3770- }
3771- if (!haveDigits ) {
3772- throw new NumberFormatException ("No digits" );
3773- }
3774- if (haveSmallInt ) {
3775- bigint [0 ] = ((short )(smallInt & 0xffff ));
3776- bigint [1 ] = ((short )((smallInt >> 16 ) & 0xffff ));
3908+ if (haveSmallInt ) {
3909+ bigint [0 ] = ((short )(smallInt & 0xffff ));
3910+ bigint [1 ] = ((short )((smallInt >> 16 ) & 0xffff ));
3911+ }
37773912 }
37783913 int count = CountWords (bigint , bigint .length );
37793914 return (count == 0 ) ? BigInteger .ZERO : new BigInteger (
0 commit comments