The article looked after the feeling benefited, so left to prepare for the temperature: http://www.congmo.net/blog/2012/03/05/Long-toString/
It took nearly two weeks to finish the Long.java, and we can say that the harvest is quite abundant. Also spent a few days of thinking how to write out, suffer from the lack of good ideas, and can not be here to waste time. So I was ready to write it out. Very casually write, think of where to write where. Ready to paste a lot of source code, attach my personal understanding.
ToString (long i, int radix)
First let's witness the powerful tostring method in the next long.
public static String toString (long i, int radix) { if (Radix < Character.min_radix | | Radix > Character.max_radi X) radix = ten; if (radix = =) return toString (i); char[] buf = new char[65]; int charpos = +; Boolean negative = (i < 0); if (!negative) { i =-i; } while (i <=-radix) { buf[charpos--] = integer.digits[(int) (-(i% radix))]; i = I/radix; } Buf[charpos] = integer.digits[(int) (-i)]; if (negative) { Buf[--charpos] = '-'; } return new String (BUF, Charpos, (65-charpos));}
The second parameter, radix, is the binary number, and the range is: 2-36. Everyone knows that the 1 binary is meaningless, so the number of binary numbers starting from 2, I have been in doubt about 36, although it is 0-9 and a-Z altogether 36 characters, So the maximum number of digits is defined as 36. But there are also uppercase letters, and there are 26 of them, so you can define the maximum of 62 binary. Perhaps there is a source here I do not know, I oschina on the question, but there is no satisfactory answer to me.
Radix if it is not in the 2-36 range, the default is 10 binary. In the case of a 10 binary, long has a tostring method that converts a 10-bit long into a string, which is later.
The non-10-binary ToString is here for processing.
char[] buf = new CHAR[65];
at first I didn't understand why I had to declare a char array of length 65, and the long64 bit would suffice. A careful study of the discovery, more than the declaration of one is to prepare for negative numbers, if it is positive then it is only used 64 bits (here is not rigorous, but first put 65 this problem clear). Take a look at the following code:
if (negative) { Buf[--charpos] = '-'; } return new String (BUF, Charpos, (65-charpos));
Clearly, this buf0 If there is a value, then it is only possible "-" and will not be any other value. The last line is also very well understood, with a few, then passed to the string constructor several. So the above-mentioned "positive 64-bit" is not rigorous.
I like the use of negative here, not very clever, but avoid the difference between positive and negative.
if (!negative) { i =-i; }
At first I also didn't understand why a positive number should be converted to a negative number and then processed? Look at the following code snippet:
while (i <=-radix) { buf[charpos--] = integer.digits[(int) (-(i% radix))]; i = I/radix;} Buf[charpos] = integer.digits[(int) (-i)];
Look at the inside and outside of the while, assuming that if I is precisely the negative unknown, then these two places cannot be uniformly used-(I radix) and-I. So I converted the I to a negative value in advance. Integer.digits is a clever thing to be able to handle the conversion of 2-36 binary. It is defined as: Liquid Error:flag value is invalid:-O "" for example, radix = 2, then I% radix can only be 0 or 1, corresponding to digits0 or digits1, And so on
I think this ToString has been introduced in detail enough. In addition, the source code will convert I to negative, then the conversion to a positive number will certainly be set up. So I made a little change:
Final static char[] digits = { ' 0 ', ' 1 ', ' 2 ', ' 3 ', ' 4 ', ' 5 ', ' 6 ', ' 7 ', ' 8 ', ' 9 ', ' A ', ' B ', ' c ', ' d ', ' e ', ' f ', ' g ', ' h ', ' I ', ' j ', ' K ', ' l ', ' m ', ' n ', ' o ', ' P ', ' Q ', ' R ', ' s ', ' t ', ' u ', ' V ' , ' W ', ' x ', ' y ', ' z '};p ublic static String toString (long i, int radix) { if (Radix < Character.min_radix | | rad IX > Character.max_radix) RADIX = ten; if (radix = =) return "";//Not the focus, skip directly over char[] buf = new char[65]; int charpos = +; Boolean negative = (i < 0); if (negative) { i =-i; } while (I >= radix) { buf[charpos--] = digits[(int) ((i% radix))]; i = I/radix; } Buf[charpos] = digits[(int) (i)]; if (negative) { Buf[--charpos] = '-'; } return new String (BUF, Charpos, (65-charpos));}
It still works Oh!
System.out.println (Long.tostring ( -8l, 2)); System.out.println (toString ( -8l,2));
Output results: -1000 -1000
ToString (Long i)
This tostring method is used to convert parameter I to a string in decimal form, and ToString (long i) itself is very simple, with the core being GetChars (long i, int index, char buf). Then we will see how they all come true.
public static String toString (long i) { if (i = = long.min_value) eturn " -9223372036854775808"; int size = (I < 0)? Stringsize (-i) + 1:stringsize (i); char[] buf = new Char[size]; GetChars (i, size, buf); return new String (0, size, buf);}
static void GetChars (long i, int index, char[] buf) {long q; int R; int charpos = index; char sign = 0; if (I < 0) {sign = '-'; i =-I.; }//Get 2 digits/iteration using longs until quotient fits into an int//8-4 byte while (i > Integer.max_value) { Q = i/100; Really:r = i-(q * 100); R = (int) (I-((Q << 6) + (q << 5) + (Q << 2)); i = q; Buf[--charpos] = Integer.digitones[r]; Buf[--charpos] = Integer.digittens[r]; }//Get 2 digits/iteration using ints//4-2 byte int Q2; int i2 = (int) i; while (I2 >= 65536) {q2 = i2/100; Really:r = i2-(q * 100); R = i2-((Q2 << 6) + (Q2 << 5) + (Q2 << 2)); i2 = Q2; Buf[--charpos] = Integer.digitones[r]; Buf[--charpos] = Integer.digittens[r]; }//Fall thru to fast mode for smaller numbers//assert (I2 <= 65536, I2); 2-0 bytes for (;;) {q2 = (I2 * 52429) >>> (16+3); R = i2-((Q2 << 3) + (Q2 << 1)); // R = i2-(q2*10) ... buf[--charpos] = integer.digits[r]; i2 = Q2; if (I2 = = 0) break; } if (sign! = 0) {Buf[--charpos] = sign; }}
This getchars is a variety of ingenious, first to look at the following picture:
as can be seen, a long type of number is divided into 3 segments: 8-4 bytes, 4-2 bytes, 2-0 bytes. Three paragraphs were dealt with separately. Here is an analysis of the ingenious.
8-4 byte processing
The main purpose of this paragraph is to deal with a long type of number by converting it to int after it has been processed. Almost every line in this while is classic, first this line: R = (int) (I-((Q << 6) + (q << 5) + (Q << 2))); It is very clever to use the efficient displacement operation to complete R = i-(q * 100). Actually doing this in order to get the last two bits of I, such as 2147483649 such a long, after this step R = 49.
Then something more ingenious happened again. That's the ingenious design of the digitones and Digittens in the integer. Let's see how smart these two arrays are.
Final static char [] Digittens = {' 0 ', ' 0 ', ' 0 ', ' 0 ', ' 0 ', ' 0 ', ' 0 ', ' 0 ', ' 0 ', ' 0 ', ' 1 ', ' 1 ', ' 1 ', ' 1 ', ' 1 ', ' 1 ', ' 1 ', ' 1 ', ' 1 ', ' 1 ', ' 2 ', ' 2 ', ' 2 ', ' 2 ', ' 2 ', ' 2 ', ' 2 ', ' 2 ', ' 2 ', ' 2 ', ' 3 ', ' 3 ', ' 3 ', ' 3 ', ' 3 ', ' 3 ', ' 3 ', ' 3 ', ' 3 ', ' 4 ', ' 4 ', ' 4 ', ' 4 ', ' 4 ', ' 4 ', ' 4 ', ' 4 ', ' 4 ', ' 5 ', ' 5 ', ' 5 ', ' 5 ', ' 5 ', ' 5 ', ' 5 ', ' 5 ', ' 5 ', ' 5 ', ' 6 ', ' 6 ', ' 6 ', ' 6 ', ' 6 ', ' 6 ', ' 6 ', ' 6 ', ' 7 ', ' 7 ', ' 7 ', ' 7 ', ' 7 ', ' 7 ', ' 7 ', ' 7 ', ' 7 ', ' 7 ', ' 8 ', ' 8 ', ' 8 ', ' 8 ', ' 8 ', ' 8 ', ' 8 ', ' 8 ', ' 9 ', ' 9 ', ' 9 ', ' 9 ', ' 9 ', ' 9 ', ' 9 ', ' 9 ', ' 9 ', ' 9 ',}; Final static char [] digitones = {' 0 ', ' 1 ', ' 2 ', ' 3 ', ' 4 ', ' 5 ', ' 6 ', ' 7 ', ' 8 ', ' 9 ', ' 0 ', ' 1 ', ' 2 ', ' 3 ', ' 4 ', ' 5 ', ' 6 ', ' 7 ', ' 8 ', ' 9 ', ' 0 ', ' 1 ', ' 2 ', ' 3 ', ' 4 ', ' 5 ', ' 6 ', ' 7 ', ' 8 ', ' 9 ', ' 0 ', ' 1 ', ' 2 ', ' 3 ', ' 4 ', ' 5 ', ' 6 ', ' 7 ', ' 8 ' , ' 1 ', ' 2 ', ' 3 ', ' 4 ', ' 5 ', ' 6 ', ' 7 ', ' 8 ', ' 9 ', ' 0 ', ' 1 ', ' 2 ', ' 3 ', ' 4 ', ' 5 ', ' 6 ', ' 7 ', ' 8 ', ' 9 ', ' 0 ', ' 1 ', ' 2 ' , ' 5 ', ' 6 ', ' 7 ', ' 8 ', ' 9 ', ' 0 ', ' 1 ', ' 2 ', ' 3 ', ' 4 ', ' 5 ', ' 6 ', ' 7 ', ' 8 ', ' 9 ', ' 0 ',' 1 ', ' 2 ', ' 3 ', ' 4 ', ' 5 ', ' 6 ', ' 7 ', ' 8 ', ' 9 ', ' 0 ', ' 1 ', ' 2 ', ' 3 ', ' 4 ', ' 5 ', ' 6 ', ' 7 ', ' 8 ', ' 9 ',};
With these two ingenious arrays, the two-bit numbers are cleverly converted to 10-bit and single-digit, for example, 49 with thesetwo arrays means digittens =4 and digitones = 9. I really like this design. This makes it very simple to put a two-bit number in a char array. Again the implementation of the Q * 100, 100 = 64 + 32 + 4, through the displacement Q and add, the perfect implementation of Q * 100. Until the long can be represented by an int, go to the next paragraph.
4-2 byte processing
This code is handled almost the same as the previous paragraph, except that it deals with int instead of long.
2-0 byte processing
I've always been particularly curious about why we split this point in 2 bytes! We will describe later in the summary, in addition to this, there is a highlight: Q2 = (I2 * 52429) >>> (16+3); This is confusing me for a long time. Later inadvertently found on a post on the javaeye revealed this beautiful bright spot, 52429/524288 = 0.10000038146972656, 524288 = 1 << 19, in other words q2 = (I2 * 52429) >>& Gt (16+3); q2 = I2/10 in order to avoid inefficient division, in exchange for this way to achieve division, it is absolutely!
Summary
Summing up the GetChars this wonderful method, the reason is divided into 3 paragraphs, because the JVM implementation, the efficiency of int is the highest, long is inefficient, so the first step is to convert long to int, and then processing. Then, in order to avoid division, and multiplied by 52429 can be represented by an int, will not overflow, so there is 2 bytes of this split point. In short, the toString (long I) method is definitely a wonderful method. There are a lot of places to learn from it.
Tounsignedstring (long i, int shift)
Next let's get to know the next tounsignedstring (long i, int shift), this method is equally ingenious, a method will be a long to binary, octal, hex all done. Just by using the shift one parameter, the same is done by displacement. For example, eight, shift is 3, and then it is implemented by 1 >> 3. The only limitation is that only the number of digits is 2 of the N power.
private static String tounsignedstring (long i, int shift) { char[] buf = new char[64]; int charpos = +; int radix = 1 << shift; Long mask = radix-1; Do { Buf[--charpos] = integer.digits[(int) (I & Mask)]; I >>>= shift; while (i! = 0); return new String (BUF, Charpos, (64-charpos));}
First, by int radix = 1 << shift, the conversion of the binary number is realized,
Followed by a careful design, long mask = radix-1; Why do you have such a value? In fact, Radix is 2 of the power of N, minus 1 is all 1, such as 8-1 of the binary is 111, other similar. Then I & Mask is taken to the number of digits corresponding to the binary number. For example, 16 in the mask = 15, the corresponding binary for 1111,i & mask is to take I corresponding to the second four bits of the binary. Then the value of the corresponding binary number is obtained from the integer.digits.
Finally, through I >>>= shift; Remove the number of digits that have been made until the i=0 is reached.
Summarize
In this way, the ToString method cluster in long is resolved. In a word, long is like a treasure trove, every step is gold. Look forward to the next barrel of gold.
Java Java.lang.Long One of the following: ToString ()