Myślę, że widziałem już to pytanie zadane tutaj ...
Zavior
6
@Oli Powinien być do tego kapelusz.
Sotirios Delimanolis
12
Takie pytania, które nie ulepszają bazy danych, ale istnieją wyłącznie jako przynęta na kliknięcia, są niezawodnym sposobem na anulowanie gry Hat w przyszłości. Proszę, nie psuj gry, wygłupiając się za nią.
Blazemonger
Odpowiedzi:
256
Liczba 4946144450195624mieści się w 64 bitach, jej reprezentacja binarna to:
Program dekoduje znak dla każdej 5-bitowej grupy, od prawej do lewej
00100|01100|10010|01111|10111|11111|01111|01100|01100|00101|01000
d | l | r | o | w | | o | l | l | e | h
5-bitowa kodyfikacja
Dla 5 bitów można przedstawić 2⁵ = 32 znaki. Alfabet angielski zawiera 26 liter, co daje miejsce na 32 - 26 = 6 symboli oprócz liter. Z tym schematem kodyfikacji możesz mieć wszystkie 26 (jeden przypadek) angielskich liter i 6 symboli (między nimi spacja).
Opis algorytmu
W >>= 5pętli for przeskakuje z grupy do grupy, następnie grupa 5-bitowa zostaje odizolowana ORAZ z liczbą z maską 31₁₀ = 11111₂w zdaniul & 31
Teraz kod odwzorowuje 5-bitową wartość na odpowiadający jej 7-bitowy znak ascii. To jest trudna część, sprawdź binarne reprezentacje małych liter alfabetu w poniższej tabeli:
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
Tutaj możesz zobaczyć, że znaki ascii, które chcemy odwzorować, zaczynają się od 7 i 6 bitu set ( 11xxxxx₂) (z wyjątkiem spacji, która ma włączony tylko szósty bit), możesz kodować OR5-bitową za pomocą 96( 96₁₀ = 1100000₂) i to powinno być wystarczająco dużo, aby wykonać mapowanie, ale to nie zadziała w przypadku przestrzeni (cholera!)
Teraz wiemy, że należy zachować szczególną ostrożność, aby przetwarzać przestrzeń w tym samym czasie, co inne postacie. Aby to osiągnąć, kod włącza 7. bit (ale nie 6.) wyodrębnionej 5-bitowej grupy za pomocą OR 64 64₁₀ = 1000000₂( l & 31 | 64).
Jak dotąd grupa 5-bitowa ma postać: 10xxxxx₂(spacja byłaby 1011111₂ = 95₁₀). Jeśli potrafimy zmapować przestrzeń na 0inne wartości, które nie mają wpływu, możemy włączyć szósty bit i to wszystko. Oto, do czego mod 95dochodzi ta część, spacja 1011111₂ = 95₁₀, przy użyciu operacji mod (l & 31 | 64) % 95)cofa się tylko spacja 0, a następnie kod włącza szósty bit, dodając 32₁₀ = 100000₂
do poprzedniego wyniku, ((l & 31 | 64) % 95) + 32)przekształcając 5-bitową wartość w prawidłową ascii postać
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
Poniższy kod wykonuje proces odwrotny, biorąc pod uwagę ciąg małych liter (maksymalnie 12 znaków), zwraca 64-bitową długość, której można użyć z kodem OP:
publicclass D {publicstaticvoid 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);}}
Standardowe znaki ASCII, które są widoczne, mieszczą się w zakresie od 32 do 127.
Dlatego widzisz tam 32 i 95 (127 - 32).
W rzeczywistości każdy znak jest tutaj mapowany na 5 bitów (możesz znaleźć kombinację 5 bitów dla każdego znaku), a następnie wszystkie bity są łączone, aby utworzyć dużą liczbę.
Długie dodatnie to liczby 63-bitowe, wystarczająco duże, aby pomieścić zaszyfrowaną postać 12 znaków. Jest więc wystarczająco duża, aby pomieścić Hello word, ale w przypadku większych tekstów należy użyć większych liczb lub nawet BigInteger.
W aplikacji chcieliśmy przesłać widoczne znaki angielskie, perskie i symbole przez SMS. Jak widzisz, są32 (number of Persian chars) + 95 (number of English characters and standard visible symbols) = 127 możliwe wartości, które można przedstawić za pomocą 7 bitów.
Przekonwertowaliśmy każdy znak UTF-8 (16-bitowy) na 7 bitów i uzyskaliśmy współczynnik kompresji ponad 56%. Mogliśmy więc wysyłać teksty o podwójnej długości w tej samej liczbie SMS-ów. (W pewnym sensie to samo wydarzyło się tutaj).
Zakodowałeś znaki jako wartości 5-bitowe i spakowałeś 11 z nich w 64-bitową długość.
(packedValues >> 5*i) & 31 jest i-tą zakodowaną wartością z zakresu 0-31.
Jak mówisz, najtrudniejsze jest zakodowanie przestrzeni. Małe litery angielskie zajmują ciągły zakres 97-122 w Unicode (i ascii i większości innych kodowań), ale spacja to 32.
Aby temu zaradzić, użyłeś trochę arytmetyki. ((x+64)%95)+32jest prawie takie samo jak x + 96(zwróć uwagę, jak bitowe OR jest równoważne dodawaniu w tym przypadku), ale gdy x = 31, otrzymujemy 32.
Powinieneś wyjaśnić, co robisz, zamiast publikować kolejną zagadkę
Aleksandr Dubinsky
1
Sugeruję, abyś zainwestował trochę wysiłku w znalezienie witryny (być może jakiejś Beta StackExchange?), W której mile widziane jest zgłaszanie zabawnych zagadek. Stack Overflow to witryna z pytaniami i odpowiedziami, która jest ściśle wymuszona.
Marko Topolnik
1
@MarkoTopolnik Nienawidziłbym życia w świecie, w którym wszystkie zasady lub cele byłyby tak surowo egzekwowane, że nigdy nie pozwalały na żadne wyjątki. Nie wspominając o tym, że takich wyjątków jest niezliczona ilość.
גלעד ברקן
1
Ja też bym chciał, ale SO jest takim światem w niezwykle dużym stopniu. Pewnie, że są wyjątki nawet tutaj, ale nie są one mile widziane .
Marko Topolnik
1
Kolejnych 15 podzielało zdanie Alexandra. I masz rację wskazując, że samo pytanie jest nieodpowiednie dla SO, jak skomentowano poniżej.
Marko Topolnik
3
Bez Oracletagu trudno było zobaczyć to pytanie. Przyniosła mnie tu nagroda czynna. Chciałbym, żeby pytanie zawierało również inne istotne tagi technologiczne :-(
Przeważnie pracuję Oracle database, więc wykorzystałbym trochę Oraclewiedzy do interpretacji i wyjaśnienia :-)
Zamieńmy liczbę 4946144450195624na binary. W tym celu używam małego o functionnazwie dec2bin, czyli dziesiętnego na binarny .
SQL> CREATE OR REPLACE FUNCTION dec2bin (N in number) RETURN varchar2 IS
2 binval varchar2(64);3 N2 number := N;4 BEGIN
5while( N2 >0) loop
6 binval := mod(N2,2)|| binval;7 N2 := trunc( N2 /2);8 end loop;9return binval;10 END dec2bin;11/Function created.
SQL> show errors
No errors.
SQL>
Użyjmy funkcji, aby uzyskać wartość binarną -
SQL> SELECT dec2bin(4946144450195624) FROM dual;
DEC2BIN(4946144450195624)--------------------------------------------------------------------------------10001100100100111110111111110111101100011000010101000
SQL>
Teraz haczykiem jest 5-bitkonwersja. Rozpocznij grupowanie od prawej do lewej z 5 cyframi w każdej grupie. Otrzymujemy: -
Zostałyby nam w końcu tylko 3 cyfry, które kończą się po prawej stronie. Ponieważ w konwersji binarnej mieliśmy łącznie 53 cyfry.
SQL> SELECT LENGTH(dec2bin(4946144450195624)) FROM dual;
LENGTH(DEC2BIN(4946144450195624))---------------------------------53
SQL>
hello worldłącznie ma 11 znaków (łącznie ze spacjami), więc musimy dodać 2 bity do ostatniej grupy, w której pozostały nam tylko 3 bity po zgrupowaniu.
Teraz musimy przekonwertować go na 7-bitową wartość ascii. Dla znaków jest to łatwe, wystarczy ustawić szósty i siódmy bit. Dodaj 11do każdej 5-bitowej grupy powyżej po lewej.
Zinterpretujmy wartości binarne, których użyję 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);9for 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;14return result;15 END bin2dec;16/Function created.
SQL> show errors;No errors.
SQL>
Spójrzmy na każdą wartość binarną -
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
--------------------------------------------------------------------------------------------------------------100108114111119127111108108101104
SQL>
Spójrzmy, jakie to postacie: -
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>
Więc co otrzymamy w wyniku?
dlrow ⌂ olleh
To jest hello⌂world w odwrotnej kolejności. Jedynym problemem jest przestrzeń . Powód jest dobrze wyjaśniony przez @higuaro w jego odpowiedzi. Szczerze mówiąc, nie mogłem sam zinterpretować problemu przestrzeni za pierwszym razem, dopóki nie zobaczyłem wyjaśnienia podanego w jego odpowiedzi.
Odpowiedzi:
Liczba
4946144450195624
mieści się w 64 bitach, jej reprezentacja binarna to:Program dekoduje znak dla każdej 5-bitowej grupy, od prawej do lewej
5-bitowa kodyfikacja
Dla 5 bitów można przedstawić 2⁵ = 32 znaki. Alfabet angielski zawiera 26 liter, co daje miejsce na 32 - 26 = 6 symboli oprócz liter. Z tym schematem kodyfikacji możesz mieć wszystkie 26 (jeden przypadek) angielskich liter i 6 symboli (między nimi spacja).
Opis algorytmu
W
>>= 5
pętli for przeskakuje z grupy do grupy, następnie grupa 5-bitowa zostaje odizolowana ORAZ z liczbą z maską31₁₀ = 11111₂
w zdaniul & 31
Teraz kod odwzorowuje 5-bitową wartość na odpowiadający jej 7-bitowy znak ascii. To jest trudna część, sprawdź binarne reprezentacje małych liter alfabetu w poniższej tabeli:
Tutaj możesz zobaczyć, że znaki ascii, które chcemy odwzorować, zaczynają się od 7 i 6 bitu set (
11xxxxx₂
) (z wyjątkiem spacji, która ma włączony tylko szósty bit), możesz kodowaćOR
5-bitową za pomocą96
(96₁₀ = 1100000₂
) i to powinno być wystarczająco dużo, aby wykonać mapowanie, ale to nie zadziała w przypadku przestrzeni (cholera!)Teraz wiemy, że należy zachować szczególną ostrożność, aby przetwarzać przestrzeń w tym samym czasie, co inne postacie. Aby to osiągnąć, kod włącza 7. bit (ale nie 6.) wyodrębnionej 5-bitowej grupy za pomocą OR 64
64₁₀ = 1000000₂
(l & 31 | 64
).Jak dotąd grupa 5-bitowa ma postać:
10xxxxx₂
(spacja byłaby1011111₂ = 95₁₀
). Jeśli potrafimy zmapować przestrzeń na0
inne wartości, które nie mają wpływu, możemy włączyć szósty bit i to wszystko. Oto, do czegomod 95
dochodzi ta część, spacja1011111₂ = 95₁₀
, przy użyciu operacji mod(l & 31 | 64) % 95)
cofa się tylko spacja0
, a następnie kod włącza szósty bit, dodając32₁₀ = 100000₂
do poprzedniego wyniku,((l & 31 | 64) % 95) + 32)
przekształcając 5-bitową wartość w prawidłową ascii postaćPoniższy kod wykonuje proces odwrotny, biorąc pod uwagę ciąg małych liter (maksymalnie 12 znaków), zwraca 64-bitową długość, której można użyć z kodem OP:
źródło
Dodanie wartości do powyższych odpowiedzi. Poniższy skrypt groovy wyświetla wartości pośrednie.
Tutaj jest
źródło
Ciekawy!
Standardowe znaki ASCII, które są widoczne, mieszczą się w zakresie od 32 do 127.
Dlatego widzisz tam 32 i 95 (127 - 32).
W rzeczywistości każdy znak jest tutaj mapowany na 5 bitów (możesz znaleźć kombinację 5 bitów dla każdego znaku), a następnie wszystkie bity są łączone, aby utworzyć dużą liczbę.
Długie dodatnie to liczby 63-bitowe, wystarczająco duże, aby pomieścić zaszyfrowaną postać 12 znaków. Jest więc wystarczająco duża, aby pomieścić
Hello word
, ale w przypadku większych tekstów należy użyć większych liczb lub nawet BigInteger.W aplikacji chcieliśmy przesłać widoczne znaki angielskie, perskie i symbole przez SMS. Jak widzisz, są
32 (number of Persian chars) + 95 (number of English characters and standard visible symbols) = 127
możliwe wartości, które można przedstawić za pomocą 7 bitów.Przekonwertowaliśmy każdy znak UTF-8 (16-bitowy) na 7 bitów i uzyskaliśmy współczynnik kompresji ponad 56%. Mogliśmy więc wysyłać teksty o podwójnej długości w tej samej liczbie SMS-ów. (W pewnym sensie to samo wydarzyło się tutaj).
źródło
| 64
robi.Otrzymujesz wynik, który jest
char
reprezentacją poniższych wartościźródło
Zakodowałeś znaki jako wartości 5-bitowe i spakowałeś 11 z nich w 64-bitową długość.
(packedValues >> 5*i) & 31
jest i-tą zakodowaną wartością z zakresu 0-31.Jak mówisz, najtrudniejsze jest zakodowanie przestrzeni. Małe litery angielskie zajmują ciągły zakres 97-122 w Unicode (i ascii i większości innych kodowań), ale spacja to 32.
Aby temu zaradzić, użyłeś trochę arytmetyki.
((x+64)%95)+32
jest prawie takie samo jakx + 96
(zwróć uwagę, jak bitowe OR jest równoważne dodawaniu w tym przypadku), ale gdy x = 31, otrzymujemy32
.źródło
Wyświetla „hello world” z podobnego powodu:
ale z nieco innego powodu niż ten:
źródło
Bez
Oracle
tagu trudno było zobaczyć to pytanie. Przyniosła mnie tu nagroda czynna. Chciałbym, żeby pytanie zawierało również inne istotne tagi technologiczne :-(Przeważnie pracuję
Oracle database
, więc wykorzystałbym trochęOracle
wiedzy do interpretacji i wyjaśnienia :-)Zamieńmy liczbę
4946144450195624
nabinary
. W tym celu używam małego ofunction
nazwie dec2bin, czyli dziesiętnego na binarny .Użyjmy funkcji, aby uzyskać wartość binarną -
Teraz haczykiem jest
5-bit
konwersja. Rozpocznij grupowanie od prawej do lewej z 5 cyframi w każdej grupie. Otrzymujemy: -Zostałyby nam w końcu tylko 3 cyfry, które kończą się po prawej stronie. Ponieważ w konwersji binarnej mieliśmy łącznie 53 cyfry.
hello world
łącznie ma 11 znaków (łącznie ze spacjami), więc musimy dodać 2 bity do ostatniej grupy, w której pozostały nam tylko 3 bity po zgrupowaniu.Więc teraz mamy: -
Teraz musimy przekonwertować go na 7-bitową wartość ascii. Dla znaków jest to łatwe, wystarczy ustawić szósty i siódmy bit. Dodaj
11
do każdej 5-bitowej grupy powyżej po lewej.To daje :-
Zinterpretujmy wartości binarne, których użyję
binary to decimal conversion function
.Spójrzmy na każdą wartość binarną -
Spójrzmy, jakie to postacie: -
Więc co otrzymamy w wyniku?
dlrow ⌂ olleh
To jest hello⌂world w odwrotnej kolejności. Jedynym problemem jest przestrzeń . Powód jest dobrze wyjaśniony przez @higuaro w jego odpowiedzi. Szczerze mówiąc, nie mogłem sam zinterpretować problemu przestrzeni za pierwszym razem, dopóki nie zobaczyłem wyjaśnienia podanego w jego odpowiedzi.
źródło
Zauważyłem, że kod jest nieco łatwiejszy do zrozumienia po przetłumaczeniu na PHP, w następujący sposób:
Zobacz kod na żywo
źródło
out.println ((char) (((l & 31 | 64)% 95) + 32/1002439 * 1002439));
Aby to zrobić: 3
źródło