これは「hello world」をどのように出力しますか?


163

私はこの奇妙なことを発見しました:

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

出力:

hello world

これはどのように作動しますか?


14
これは自分で理解できるということです。
Sotirios Delimanolis 2013

30
はい。認めます...私は帽子を釣っています:)
ボヘミアン

6
私は..私はこの質問をする前に、ここで尋ねた見てきたと思います
Zavior

6
@オリそのための帽子があるはずです。
Sotirios Delimanolis 2013

12
データベースを改善するのではなく、クリックベイトとしてのみ存在するこのような質問は、Hatゲームを将来キャンセルする確実な方法です。それのために売春婦によってゲームを台無しにしないでください。
Blazemonger 2013

回答:


256

数値は494614445019562464ビットに適合し、そのバイナリ表現は次のとおりです。

 10001100100100111110111111110111101100011000010101000

プログラムは、5ビットグループごとに文字を右から左にデコードします。

 00100|01100|10010|01111|10111|11111|01111|01100|01100|00101|01000
   d  |  l  |  r  |  o  |  w  |     |  o  |  l  |  l  |  e  |  h

5ビットのコード化

5ビットの場合、2⁵= 32文字を表すことができます。英語のアルファベットには26文字が含まれます。これにより、文字とは別に32〜26 = 6個の記号が入ります。このコード化スキームでは、26(すべて1ケース)の英字と6つの記号(スペース)を使用できます。

アルゴリズムの説明

>>= 5forループでは、その後、5ビットのグループは、マスクと番号を論理積単離取得し、グループにグループからジャンプ31₁₀ = 11111₂文でl & 31

ここで、コードは5ビットの値を対応する7ビットのASCII文字にマッピングします。これは注意が必要な部分です。次の表の小文字のアルファベットのバイナリ表現を確認してください。

  ascii   |     ascii     |    ascii     |    algorithm
character | decimal value | binary value | 5-bit codification 
--------------------------------------------------------------
  space   |       32      |   0100000    |      11111
    a     |       97      |   1100001    |      00001
    b     |       98      |   1100010    |      00010
    c     |       99      |   1100011    |      00011
    d     |      100      |   1100100    |      00100
    e     |      101      |   1100101    |      00101
    f     |      102      |   1100110    |      00110
    g     |      103      |   1100111    |      00111
    h     |      104      |   1101000    |      01000
    i     |      105      |   1101001    |      01001
    j     |      106      |   1101010    |      01010
    k     |      107      |   1101011    |      01011
    l     |      108      |   1101100    |      01100
    m     |      109      |   1101101    |      01101
    n     |      110      |   1101110    |      01110
    o     |      111      |   1101111    |      01111
    p     |      112      |   1110000    |      10000
    q     |      113      |   1110001    |      10001
    r     |      114      |   1110010    |      10010
    s     |      115      |   1110011    |      10011
    t     |      116      |   1110100    |      10100
    u     |      117      |   1110101    |      10101
    v     |      118      |   1110110    |      10110
    w     |      119      |   1110111    |      10111
    x     |      120      |   1111000    |      11000
    y     |      121      |   1111001    |      11001
    z     |      122      |   1111010    |      11010

ここで、マップするASCII文字が7番目と6番目のビットセット(11xxxxx₂)で始まることがわかります(6ビット目のみがオンになっているスペースを除く)OR。5ビットのコード化は9696₁₀ = 1100000₂)、それはする必要がありますマッピングを行うのに十分ですが、それはスペースでは機能しません(スペースをくすぐります!)

これで、他のキャラクターと同時にスペースを処理するために特別な注意を払う必要があることがわかりました。これを達成するために、コードがOR 64で抽出した5ビットのグループに(6日ではなく)に7ビットをオン64₁₀ = 1000000₂l & 31 | 64)で)。

これまでのところ、5ビットグループの形式は次のとおりです10xxxxx₂(スペースはになります1011111₂ = 95₁₀)。スペースを0他の値に影響を与えないようにマップできる場合は、6番目のビットをオンにできます。これですべてです。ここでは何であるmod 95スペースがあり、一部が再生するために来1011111₂ = 95₁₀たMOD操作使用して、(l & 31 | 64) % 95)唯一のスペースがに戻りを0し、この後に、コードが追加することによって、上の6ビット目をオン32₁₀ = 100000₂ 、前の結果に((l & 31 | 64) % 95) + 32)有効なASCIIに5ビットの値を変換しますキャラクター

isolates 5 bits --+          +---- takes 'space' (and only 'space') back to 0
                  |          |
                  v          v
               (l & 31 | 64) % 95) + 32
                       ^           ^ 
       turns the       |           |
      7th bit on ------+           +--- turns the 6th bit on

次のコードは、小文字の文字列(最大12文字)を指定すると、逆のプロセスを実行し、OPのコードで使用できる64ビット長の値を返します。

public class D {
    public static void main(String... args) {
        String v = "hello test";
        int len = Math.min(12, v.length());
        long res = 0L;
        for (int i = 0; i < len; i++) {
            long c = (long) v.charAt(i) & 31;
            res |= ((((31 - c) / 31) * 31) | c) << 5 * i;
        }
        System.out.println(res);
    }
}    

11
この答えは謎を残しません。むしろ、それはあなたのためにあなたの考えをします。

7
答えは質問よりもさらに難しい:D
Yazan

1
説明はもっとすっきりしています:)
Prashant 2015年

40

上記の回答にいくつかの値を追加します。次のgroovyスクリプトは中間値を出力します。

String getBits(long l) {
return Long.toBinaryString(l).padLeft(8,'0');
}

for (long l = 4946144450195624l; l > 0; l >>= 5){
    println ''
    print String.valueOf(l).toString().padLeft(16,'0')
    print '|'+ getBits((l & 31 ))
    print '|'+ getBits(((l & 31 | 64)))
    print '|'+ getBits(((l & 31 | 64)  % 95))
    print '|'+ getBits(((l & 31 | 64)  % 95 + 32))

    print '|';
    System.out.print((char) (((l & 31 | 64) % 95) + 32));
}

ここにあります

4946144450195624|00001000|01001000|01001000|01101000|h
0154567014068613|00000101|01000101|01000101|01100101|e
0004830219189644|00001100|01001100|01001100|01101100|l
0000150944349676|00001100|01001100|01001100|01101100|l
0000004717010927|00001111|01001111|01001111|01101111|o
0000000147406591|00011111|01011111|00000000|00100000| 
0000000004606455|00010111|01010111|01010111|01110111|w
0000000000143951|00001111|01001111|01001111|01101111|o
0000000000004498|00010010|01010010|01010010|01110010|r
0000000000000140|00001100|01001100|01001100|01101100|l
0000000000000004|00000100|01000100|01000100|01100100|d

26

面白い!

表示される標準ASCII文字は、32〜127の範囲です。

そのため、32と95(127-32)が表示されます。

実際、各文字はここで5ビットにマッピングされ(各文字の5ビットの組み合わせを見つけることができます)、すべてのビットが連結されて大きな数を形成します。

正のlongは63ビットの数字で、12文字の暗号化された形式を保持するのに十分な大きさです。したがって、を保持するのHello wordに十分な大きさですが、より大きなテキストの場合は、より大きな数、またはBigIntegerを使用する必要があります。


アプリケーションで、SMSを介して目に見える英語の文字、ペルシャ語の文字、記号を転送したかった。ご覧のとおり32 (number of Persian chars) + 95 (number of English characters and standard visible symbols) = 127、可能な値は7ビットで表すことができます。

各UTF-8(16ビット)文字を7ビットに変換し、56%以上の圧縮率を得ました。したがって、同じ数のSMSで2倍の長さのテキストを送信できます。(それはどういうわけかここで同じことが起こりました)。


OPのコードでは、さらに多くのことが行われています。たとえば、これはが何をし| 64ているかを実際に説明するものではありません。
Ted Hopp

1
@アミール:スペース文字を取得する必要があるため、実際には95があります。
Bee

17

あなたはたまたまchar以下の値の表現である結果を得ています

104 -> h
101 -> e
108 -> l
108 -> l
111 -> o
32  -> (space)
119 -> w
111 -> o
114 -> r
108 -> l
100 -> d

16

文字を5ビット値としてエンコードし、そのうちの11文字を64ビット長にパックしました。

(packedValues >> 5*i) & 31 範囲0〜31のi番目のエンコードされた値です。

あなたが言うように、難しい部分はスペースをエンコードすることです。小文字の英字は、Unicode(およびascii、およびその他のほとんどのエンコーディング)で97〜122の連続した範囲を占めますが、スペースは32です。

これを克服するために、いくつかの算術を使用しました。((x+64)%95)+32とほとんど同じですx + 96(この場合、ビット単位のORが加算に相当することに注意してください)。ただし、x = 31の場合はになり32ます。


6

同様の理由で「hello world」を出力します。

for (int k=1587463874; k>0; k>>=3)
     System.out.print((char) (100 + Math.pow(2,2*(((k&7^1)-1)>>3 + 1) + (k&7&3)) + 10*((k&7)>>2) + (((k&7)-7)>>3) + 1 - ((-(k&7^5)>>3) + 1)*80));

しかし、これとは少し異なる理由で:

for (int k=2011378; k>0; k>>=2)
    System.out.print((char) (110 + Math.pow(2,2*(((k^1)-1)>>21 + 1) + (k&3)) - ((k&8192)/8192 + 7.9*(-(k^1964)>>21) - .1*(-((k&35)^35)>>21) + .3*(-((k&120)^120)>>21) + (-((k|7)^7)>>21) + 9.1)*10));

18
別の謎を投稿するのではなく、何をしているのかを説明する必要があります
Aleksandr Dubinsky

1
楽しいなぞなぞの投稿を歓迎するサイト(おそらくベータ版のStackExchange)を見つけるために、ある程度の労力を費やすことをお勧めします。Stack Overflowは、厳密に適用されるQ&Aサイトです。
Marko Topolnik、2014

1
@MarkoTopolnikすべてのルールや焦点が非常に厳格に施行されており、例外を決して許可しない世界に住むのは嫌いです。SOにはそのような例外が無数にあることは言うまでもありません。
גלעדברקן

1
私もそうしますが、SOは非常に広い範囲でそのような世界です。もちろん、ここにも例外はありますが、歓迎されません。
Marko Topolnik、2014年

1
別の15人はアレクサンダーの感情を共有した。そして、あなたは質問の下でコメントされているように、質問自体がSOには不適切であることを指摘するのは正しいです。
Marko Topolnik、2014年

3

Oracleタグがないと、この質問を見ることは困難でした。アクティブな報奨金で私をここに連れてきました。質問に他の関連する技術タグもあったらいいのに:-(

私は主にで作業するOracle databaseので、いくつかのOracle知識を使用して解釈し、説明します:-)

数値4946144450195624をに変換しましょうbinary。そのために私は小さなfunction dec2binと呼ばれるつまり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>

関数を使用してバイナリ値を取得しましょう-

SQL> SELECT dec2bin(4946144450195624) FROM dual;

DEC2BIN(4946144450195624)
--------------------------------------------------------------------------------
10001100100100111110111111110111101100011000010101000

SQL>

今キャッチは 5-bit変換です。各グループに5桁ずつ、右から左にグループ化を開始します。我々が得る :-

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

最終的には3つだけ残されます彼が右で終わる桁ます。それは、バイナリ変換で合計53桁を使用したためです。

SQL> SELECT LENGTH(dec2bin(4946144450195624)) FROM dual;

LENGTH(DEC2BIN(4946144450195624))
---------------------------------
                               53

SQL>

hello world 合計 11文字(スペースを含む)なので、2文字追加する必要があります、グループ化後に3ビットしか残っていない最後のグループにビットをます。

だから、今私たちは持っています:-

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

次に、それを7ビットのASCII値に変換する必要があります。キャラクターは簡単です。6番目と7番目のビットを設定するだけです。11左上の各5ビットグループに追加します。

それは与える:-

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

バイナリ値を解釈してみましょう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>

各バイナリ値を見てみましょう-

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>

それらがどんな文字であるか見てみましょう:-

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>

では、出力には何が含まれますか?

dlrow⌂olleh

それは逆にhello⌂worldです。唯一の問題はスペースです。そしてその理由は@higuaroの回答でよく説明されています。正直に言って、彼の答えにある説明を見るまで、私は最初の試みで自分自身で宇宙問題を解釈することができませんでした。


1

次のように、PHPに変換するとコードが少しわかりやすくなりました。

<?php

$result=0;
$bignum = 4946144450195624;
for (; $bignum > 0; $bignum >>= 5){
    $result = (( $bignum & 31 | 64) % 95) + 32;
    echo chr($result);
}

ライブコードを見る


0

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

それをキャップにする:3


1
何をしているのか、その理由を説明してください。
fedorqui 'SO stop harming' 2014
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.