@@ -3950,35 +3950,66 @@ public String toString(int radix) {
3950
3950
if (radix < Character .MIN_RADIX || radix > Character .MAX_RADIX )
3951
3951
radix = 10 ;
3952
3952
3953
- // If it's small enough, use smallToString.
3954
- if (mag .length <= SCHOENHAGE_BASE_CONVERSION_THRESHOLD )
3955
- return smallToString (radix );
3953
+ BigInteger abs = this .abs ();
3954
+
3955
+ // Ensure buffer capacity sufficient to contain string representation
3956
+ // floor(bitLength*log(2)/log(radix)) + 1
3957
+ // plus an additional character for the sign if negative.
3958
+ int b = abs .bitLength ();
3959
+ int numChars = (int )(Math .floor (b *LOG_TWO /logCache [radix ]) + 1 ) +
3960
+ (signum < 0 ? 1 : 0 );
3961
+ StringBuilder sb = new StringBuilder (numChars );
3956
3962
3957
- // Otherwise use recursive toString, which requires positive arguments.
3958
- // The results will be concatenated into this StringBuilder
3959
- StringBuilder sb = new StringBuilder ();
3960
3963
if (signum < 0 ) {
3961
- toString (this .negate (), sb , radix , 0 );
3962
- sb .insert (0 , '-' );
3964
+ sb .append ('-' );
3963
3965
}
3964
- else
3965
- toString (this , sb , radix , 0 );
3966
+
3967
+ // Use recursive toString.
3968
+ toString (abs , sb , radix , 0 );
3966
3969
3967
3970
return sb .toString ();
3968
3971
}
3969
3972
3970
- /** This method is used to perform toString when arguments are small. */
3971
- private String smallToString (int radix ) {
3973
+ /**
3974
+ * If {@code numZeros > 0}, appends that many zeros to the
3975
+ * specified StringBuilder; otherwise, does nothing.
3976
+ *
3977
+ * @param sb The StringBuilder that will be appended to.
3978
+ * @param numZeros The number of zeros to append.
3979
+ */
3980
+ private static void padWithZeros (StringBuilder buf , int numZeros ) {
3981
+ while (numZeros >= NUM_ZEROS ) {
3982
+ buf .append (ZEROS );
3983
+ numZeros -= NUM_ZEROS ;
3984
+ }
3985
+ if (numZeros > 0 ) {
3986
+ buf .append (ZEROS , 0 , numZeros );
3987
+ }
3988
+ }
3989
+
3990
+ /**
3991
+ * This method is used to perform toString when arguments are small.
3992
+ * The value must be non-negative. If {@code digits <= 0} no padding
3993
+ * (pre-pending with zeros) will be effected.
3994
+ *
3995
+ * @param radix The base to convert to.
3996
+ * @param sb The StringBuilder that will be appended to in place.
3997
+ * @param digits The minimum number of digits to pad to.
3998
+ */
3999
+ private void smallToString (int radix , StringBuilder buf , int digits ) {
4000
+ assert signum >= 0 ;
4001
+
3972
4002
if (signum == 0 ) {
3973
- return "0" ;
4003
+ padWithZeros (buf , digits );
4004
+ return ;
3974
4005
}
3975
4006
3976
4007
// Compute upper bound on number of digit groups and allocate space
3977
4008
int maxNumDigitGroups = (4 *mag .length + 6 )/7 ;
3978
- String digitGroup [] = new String [maxNumDigitGroups ];
4009
+ long [] digitGroups = new long [maxNumDigitGroups ];
3979
4010
3980
4011
// Translate number to string, a digit group at a time
3981
- BigInteger tmp = this . abs () ;
4012
+ BigInteger tmp = this ;
3982
4013
int numGroups = 0 ;
3983
4014
while (tmp .signum != 0 ) {
3984
4015
BigInteger d = longRadix [radix ];
@@ -3990,33 +4021,37 @@ private String smallToString(int radix) {
3990
4021
BigInteger q2 = q .toBigInteger (tmp .signum * d .signum );
3991
4022
BigInteger r2 = r .toBigInteger (tmp .signum * d .signum );
3992
4023
3993
- digitGroup [numGroups ++] = Long . toString ( r2 .longValue (), radix );
4024
+ digitGroups [numGroups ++] = r2 .longValue ();
3994
4025
tmp = q2 ;
3995
4026
}
3996
4027
3997
- // Put sign (if any) and first digit group into result buffer
3998
- StringBuilder buf = new StringBuilder ( numGroups * digitsPerLong [ radix ]+ 1 );
3999
- if ( signum < 0 ) {
4000
- buf . append ( '-' );
4001
- }
4002
- buf . append ( digitGroup [ numGroups - 1 ] );
4028
+ // Get string version of first digit group
4029
+ String s = Long . toString ( digitGroups [ numGroups - 1 ], radix );
4030
+
4031
+ // Pad with internal zeros if necessary.
4032
+ padWithZeros ( buf , digits - ( s . length () +
4033
+ ( numGroups - 1 )* digitsPerLong [ radix ]) );
4003
4034
4004
- // Append remaining digit groups padded with leading zeros
4035
+ // Put first digit group into result buffer
4036
+ buf .append (s );
4037
+
4038
+ // Append remaining digit groups each padded with leading zeros
4005
4039
for (int i =numGroups -2 ; i >= 0 ; i --) {
4006
4040
// Prepend (any) leading zeros for this digit group
4007
- int numLeadingZeros = digitsPerLong [radix ]-digitGroup [i ].length ();
4041
+ s = Long .toString (digitGroups [i ], radix );
4042
+ int numLeadingZeros = digitsPerLong [radix ] - s .length ();
4008
4043
if (numLeadingZeros != 0 ) {
4009
- buf .append (zeros [ numLeadingZeros ] );
4044
+ buf .append (ZEROS , 0 , numLeadingZeros );
4010
4045
}
4011
- buf .append (digitGroup [ i ] );
4046
+ buf .append (s );
4012
4047
}
4013
- return buf .toString ();
4014
4048
}
4015
4049
4016
4050
/**
4017
4051
* Converts the specified BigInteger to a string and appends to
4018
4052
* {@code sb}. This implements the recursive Schoenhage algorithm
4019
- * for base conversions.
4053
+ * for base conversions. This method can only be called for non-negative
4054
+ * numbers.
4020
4055
* <p>
4021
4056
* See Knuth, Donald, _The Art of Computer Programming_, Vol. 2,
4022
4057
* Answers to Exercises (4.4) Question 14.
@@ -4026,40 +4061,34 @@ private String smallToString(int radix) {
4026
4061
* @param radix The base to convert to.
4027
4062
* @param digits The minimum number of digits to pad to.
4028
4063
*/
4029
- private static void toString (BigInteger u , StringBuilder sb , int radix ,
4030
- int digits ) {
4064
+ private static void toString (BigInteger u , StringBuilder sb ,
4065
+ int radix , int digits ) {
4066
+ assert u .signum () >= 0 ;
4067
+
4031
4068
// If we're smaller than a certain threshold, use the smallToString
4032
- // method, padding with leading zeroes when necessary.
4069
+ // method, padding with leading zeroes when necessary unless we're
4070
+ // at the beginning of the string or digits <= 0. As u.signum() >= 0,
4071
+ // smallToString() will not prepend a negative sign.
4033
4072
if (u .mag .length <= SCHOENHAGE_BASE_CONVERSION_THRESHOLD ) {
4034
- String s = u .smallToString (radix );
4035
-
4036
- // Pad with internal zeros if necessary.
4037
- // Don't pad if we're at the beginning of the string.
4038
- if ((s .length () < digits ) && (sb .length () > 0 )) {
4039
- for (int i =s .length (); i < digits ; i ++) {
4040
- sb .append ('0' );
4041
- }
4042
- }
4043
-
4044
- sb .append (s );
4073
+ u .smallToString (radix , sb , digits );
4045
4074
return ;
4046
4075
}
4047
4076
4048
- int b , n ;
4049
- b = u .bitLength ();
4050
-
4051
4077
// Calculate a value for n in the equation radix^(2^n) = u
4052
4078
// and subtract 1 from that value. This is used to find the
4053
4079
// cache index that contains the best value to divide u.
4054
- n = (int ) Math .round (Math .log (b * LOG_TWO / logCache [radix ]) / LOG_TWO - 1.0 );
4080
+ int b = u .bitLength ();
4081
+ int n = (int ) Math .round (Math .log (b * LOG_TWO / logCache [radix ]) /
4082
+ LOG_TWO - 1.0 );
4083
+
4055
4084
BigInteger v = getRadixConversionCache (radix , n );
4056
4085
BigInteger [] results ;
4057
4086
results = u .divideAndRemainder (v );
4058
4087
4059
4088
int expectedDigits = 1 << n ;
4060
4089
4061
4090
// Now recursively build the two halves of each number.
4062
- toString (results [0 ], sb , radix , digits - expectedDigits );
4091
+ toString (results [0 ], sb , radix , digits - expectedDigits );
4063
4092
toString (results [1 ], sb , radix , expectedDigits );
4064
4093
}
4065
4094
@@ -4091,14 +4120,11 @@ private static BigInteger getRadixConversionCache(int radix, int exponent) {
4091
4120
return cacheLine [exponent ];
4092
4121
}
4093
4122
4094
- /* zero[i] is a string of i consecutive zeros. */
4095
- private static String zeros [] = new String [64 ];
4096
- static {
4097
- zeros [63 ] =
4098
- "000000000000000000000000000000000000000000000000000000000000000" ;
4099
- for (int i =0 ; i < 63 ; i ++)
4100
- zeros [i ] = zeros [63 ].substring (0 , i );
4101
- }
4123
+ /* Size of ZEROS string. */
4124
+ private static int NUM_ZEROS = 63 ;
4125
+
4126
+ /* ZEROS is a string of NUM_ZEROS consecutive zeros. */
4127
+ private static final String ZEROS = "0" .repeat (NUM_ZEROS );
4102
4128
4103
4129
/**
4104
4130
* Returns the decimal String representation of this BigInteger.
0 commit comments