How does this print “hello world”?

后端 未结 9 1359
Happy的楠姐
Happy的楠姐 2021-01-29 17:33

I discovered this oddity:

for (long l = 4946144450195624l; l > 0; l >>= 5)
    System.out.print((char) (((l & 31 | 64) % 95) + 32));
9条回答
  •  慢半拍i
    慢半拍i (楼主)
    2021-01-29 18:04

    Without an Oracle tag, it was difficult to see this question. Active bounty brought me here. I wish the question had other relevant technology tags too :-(

    I mostly work with Oracle database, so I would use some Oracle knowledge to interpret and explain :-)

    Let's convert the number 4946144450195624 into binary. For that I use a small function called dec2bin i.e. decimal-to-binary.

    SQL> CREATE OR REPLACE FUNCTION dec2bin (N in number) RETURN varchar2 IS
      2    binval varchar2(64);
      3    N2     number := N;
      4  BEGIN
      5    while ( N2 > 0 ) loop
      6       binval := mod(N2, 2) || binval;
      7       N2 := trunc( N2 / 2 );
      8    end loop;
      9    return binval;
     10  END dec2bin;
     11  /
    
    Function created.
    
    SQL> show errors
    No errors.
    SQL>
    

    Let's use the function to get the binary value -

    SQL> SELECT dec2bin(4946144450195624) FROM dual;
    
    DEC2BIN(4946144450195624)
    --------------------------------------------------------------------------------
    10001100100100111110111111110111101100011000010101000
    
    SQL>
    

    Now the catch is the 5-bit conversion. Start grouping from right to left with 5 digits in each group. We get :-

    100|01100|10010|01111|10111|11111|01111|01100|01100|00101|01000
    

    We would be finally left with just 3 digits int he end at the right. Because, we had total 53 digits in the binary conversion.

    SQL> SELECT LENGTH(dec2bin(4946144450195624)) FROM dual;
    
    LENGTH(DEC2BIN(4946144450195624))
    ---------------------------------
                                   53
    
    SQL>
    

    hello world total has 11 characters(including space), so we need to add 2 bits to the last group where we were left with just 3 bits after grouping.

    So, now we have :-

    00100|01100|10010|01111|10111|11111|01111|01100|01100|00101|01000
    

    Now, we need to convert it to 7-bit ascii value. For the characters it is easy, we need to just set the 6th and 7th bit. Add 11 to each 5-bit group above to the left.

    That gives :-

    1100100|1101100|1110010|1101111|1110111|1111111|1101111|1101100|1101100|1100101|1101000
    

    Let's interpret the binary values, I will use binary to decimal conversion function.

    SQL> CREATE OR REPLACE FUNCTION bin2dec (binval in char) RETURN number IS
      2    i                 number;
      3    digits            number;
      4    result            number := 0;
      5    current_digit     char(1);
      6    current_digit_dec number;
      7  BEGIN
      8    digits := length(binval);
      9    for i in 1..digits loop
     10       current_digit := SUBSTR(binval, i, 1);
     11       current_digit_dec := to_number(current_digit);
     12       result := (result * 2) + current_digit_dec;
     13    end loop;
     14    return result;
     15  END bin2dec;
     16  /
    
    Function created.
    
    SQL> show errors;
    No errors.
    SQL>
    

    Let's look at each binary value -

    SQL> set linesize 1000
    SQL>
    SQL> SELECT bin2dec('1100100') val,
      2    bin2dec('1101100') val,
      3    bin2dec('1110010') val,
      4    bin2dec('1101111') val,
      5    bin2dec('1110111') val,
      6    bin2dec('1111111') val,
      7    bin2dec('1101111') val,
      8    bin2dec('1101100') val,
      9    bin2dec('1101100') val,
     10    bin2dec('1100101') val,
     11    bin2dec('1101000') val
     12  FROM dual;
    
           VAL        VAL        VAL        VAL        VAL        VAL        VAL        VAL        VAL     VAL           VAL
    ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ----------
           100        108        114        111        119        127        111        108        108     101           104
    
    SQL>
    

    Let's look at what characters they are :-

    SQL> SELECT chr(bin2dec('1100100')) character,
      2    chr(bin2dec('1101100')) character,
      3    chr(bin2dec('1110010')) character,
      4    chr(bin2dec('1101111')) character,
      5    chr(bin2dec('1110111')) character,
      6    chr(bin2dec('1111111')) character,
      7    chr(bin2dec('1101111')) character,
      8    chr(bin2dec('1101100')) character,
      9    chr(bin2dec('1101100')) character,
     10    chr(bin2dec('1100101')) character,
     11    chr(bin2dec('1101000')) character
     12  FROM dual;
    
    CHARACTER CHARACTER CHARACTER CHARACTER CHARACTER CHARACTER CHARACTER CHARACTER CHARACTER CHARACTER CHARACTER
    --------- --------- --------- --------- --------- --------- --------- --------- --------- --------- ---------
    d         l         r         o         w         ⌂         o         l         l         e         h
    
    SQL>
    

    So, what do we get in the output?

    d l r o w ⌂ o l l e h

    That is hello⌂world in reverse. The only issue is the space. And the reason is well explained by @higuaro in his answer. I honestly couldn't interpret the space issue myself at first attempt, until I saw the explanation given in his answer.

提交回复
热议问题