web-dev-qa-db-ja.com

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

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

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

出力:

hello world

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

161
Bohemian

上記の回答に価値を追加します。 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
39
Jayan

面白い!

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

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

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

正の長さは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倍の長さのテキストを送信できます。 (どういうわけかここで同じことが起こりました)。

26
Amir Pashazadeh

以下の値のchar表現である結果を取得しています

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

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

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

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

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

16

これは、これと同じ理由で「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));
6

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

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

番号4946144450195624binaryに変換しましょう。そのために、dec2binと呼ばれる小さなfunctionを使用します。つまり、---(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

最終的には、右端で桁だけで終了します。なぜなら、バイナリ変換では合計53桁だったからです。

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

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

SQL>

hello world totalには11文字(スペースを含む)があるため、グループ化後に3ビットだけ残った最後のグループに2ビットを追加する必要があります。

だから、今私たちは:-

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

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

それは与える:-

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>

それで、出力には何が得られますか?

d l r o w⌂o l l e h

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

3
Lalit Kumar B

次のように、コードをPHPに翻訳すると理解しやすくなりました。

<?php

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

live code を参照してください

1
slevy1

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

キャップにするには:3

0
user4329506