How does this print “hello world”?

2019-03-07 09:29发布

I discovered this oddity:

for (long l = 4946144450195624l; l > 0; l >>= 5)
    System.out.print((char) (((l & 31 | 64) % 95) + 32));

Output:

hello world

How does this work?

9条回答
Rolldiameter
2楼-- · 2019-03-07 10:25

You've encoded characters as 5-bit values and packed 11 of them into a 64 bit long.

(packedValues >> 5*i) & 31 is the i-th encoded value with a range 0-31.

The hard part, as you say, is encoding the space. The lower case english letters occupy the contiguous range 97-122 in Unicode (and ascii, and most other encodings), but the space is 32.

To overcome this, you used some arithmetic. ((x+64)%95)+32 is almost the same as x + 96 (note how bitwise OR is equivalent to addition, in this case), but when x=31, we get 32.

查看更多
男人必须洒脱
3楼-- · 2019-03-07 10:29

out.println((char) (((l & 31 | 64) % 95) + 32 / 1002439 * 1002439));

To make it caps :3

查看更多
闹够了就滚
4楼-- · 2019-03-07 10:35

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.

查看更多
登录 后发表回答