බිට්වේස් මාරුව (බිට්-ෂිෆ්ට්) ක්‍රියාකරුවන් යනු කුමක්ද සහ ඔවුන් ක්‍රියා කරන්නේ කෙසේද?


1390

මම මගේ විවේක කාලය තුළ C ඉගෙන ගැනීමට උත්සාහ කර ඇති අතර, වෙනත් භාෂාවන්ට (C #, Java, ආදිය) එකම සංකල්පයක් ඇත (බොහෝ විට එකම ක්‍රියාකරුවන්) ...

දේ මම පුදුම කරනවා ඇත, මධ්ය මට්ටමේ, කුමක් ටිකක්-මාරු කරන්නේ ( <<, >>, >>>), එය විසඳීමට දේ ප්රශ්න උපකාර කළ හැකි වන්නේ මන්ද? Gotchas වංගුව පමණ රැකගෙන ඉන්න? වෙනත් වචන වලින් කිවහොත්, නිරපේක්ෂ ආරම්භකයකුගේ සියලු යහපත්කම් ටිකක් වෙනස් කිරීමට මඟ පෙන්වීම.


2
3GL හි ඔබ බිට්ෂිෆ්ටිං භාවිතා කරන ක්‍රියාකාරී හෝ ක්‍රියාකාරී නොවන අවස්ථා ස්වල්ප වේ.
ට්‍රෝයි ඩිමොන්බ්‍රන්

16
මෙම පිළිතුරු කියවීමෙන් පසු ඔබට මෙම සබැඳි බැලීමට අවශ්‍ය විය හැකිය: graphics.stanford.edu/~seander/bithacks.html & jjj.de/bitwizardry/bitwizardrypage.html
නියපොතු

1
පරිගණකයට බිට් මාරුව අතිශයින්ම පහසු සහ වේගවත් බව සැලකිල්ලට ගැනීම වැදගත්ය. ඔබේ වැඩසටහන තුළ බිට්-ෂිෆ්ටිං භාවිතා කිරීමට ක්‍රම සොයා ගැනීමෙන්, ඔබට මතක භාවිතය සහ ක්‍රියාත්මක කිරීමේ වේලාවන් විශාල වශයෙන් අඩු කළ හැකිය.
හොයිට්මන්

Oy හොයිට්මන්: නමුත් හොඳ සම්පාදකයින් මෙම උපක්‍රම බොහොමයක් දැනටමත් දන්නා අතර එය අර්ථවත් වන ස්ථානය හඳුනා ගැනීමට වඩා හොඳ බව සලකන්න.
සෙබස්තියන් මැක්

Answers:


1719

බිට් මාරුව ක්‍රියාකරුවන් ඔවුන්ගේ නමට සමාන දේ කරයි. ඔවුන් බිටු මාරු කරයි. විවිධ මාරුව ක්‍රියාකරුවන් පිළිබඳ කෙටි (හෝ එතරම් කෙටි නොවන) හැඳින්වීමක් මෙන්න.

ක්‍රියාකරුවන්

  • >> අංක ගණිත (හෝ අත්සන් කළ) දකුණු මාරුව ක්‍රියාකරු වේ.
  • >>> තාර්කික (හෝ අත්සන් නොකළ) දකුණු මාරුව ක්‍රියාකරු වේ.
  • << වම් මාරුව ක්‍රියාකරු වන අතර තාර්කික හා අංක ගණිත මාරුවල අවශ්‍යතා සපුරාලයි.

මෙම ක්රියාකරුවන් සියලු (පූර්ණ සංඛ්යාවක් වටිනාකම් යෙදිය හැකි int, longහැකි, shortසහ byteහෝ char). සමහර භාෂාවල, මාර්‍ග ක්‍රියාකරුවන් intස්වයංක්‍රීයව ප්‍රතිස්ථාපනය කිරීමට වඩා කුඩා දත්ත සමුදායකට යෙදවීම int.

<<<එය අතිරික්තයක් වන බැවින් එය ක්‍රියාකරුවෙකු නොවන බව සලකන්න .

C සහ C ++ නිවැරදි මාරුව ක්‍රියාකරුවන් අතර වෙනස හඳුනා නොගන්නා බව සලකන්න . ඔවුන් සපයන්නේ >>ක්‍රියාකරු පමණක් වන අතර , නිවැරදි මාරුවීමේ හැසිරීම යනු අත්සන් කරන ලද වර්ග සඳහා ක්‍රියාත්මක කිරීම අර්ථ දැක්වීමකි. ඉතිරි පිළිතුර C # / Java ක්‍රියාකරුවන් භාවිතා කරයි.

(ජීසීසී සහ ක්ලැන්ග් / එල්එල්වීඑම් ඇතුළු සියලුම ප්‍රධාන ධාරාවේ, >>අත්සන් කරන ලද වර්ගවල ගණිතමය වේ. සමහර කේතයන් මෙය උපකල්පනය කරයි, නමුත් එය සම්මත සහතික කරන දෙයක් නොවේ. එය නිර්වචනය කර නැත , නමුත් ප්‍රමිතියට එය අර්ථ දැක්වීමට අවශ්‍ය වේ කෙසේ වෙතත්, negative ණ අත්සන් කළ සංඛ්‍යා වල වම් මාරුව යනු නිර්වචනය නොකළ හැසිරීමකි (අත්සන් කරන ලද පූර්ණ සංඛ්‍යා පිටාර ගැලීම). එබැවින් ඔබට ගණිතමය නිවැරදි මාරුවක් අවශ්‍ය නොවන්නේ නම්, සාමාන්‍යයෙන් අත්සන් නොකල වර්ග සමඟ ඔබේ බිටු මාරුව කිරීම හොඳ අදහසකි.)


වම් මාරුව (<<)

පූර්ණ සංඛ්‍යා බිටු මාලාවක් ලෙස මතකයේ ගබඩා කර ඇත. උදාහරණයක් ලෙස, 32-බිට් ලෙස ගබඩා කර ඇති අංක 6 intවනුයේ:

00000000 00000000 00000000 00000110

මෙම බිට් රටාව වමේ එක් ස්ථානයකට මාරු කිරීමෙන් ( 6 << 1) අංක 12 ට හේතු වේ:

00000000 00000000 00000000 00001100

ඔබට පෙනෙන පරිදි, ඉලක්කම් එක් ස්ථානයකින් වමට මාරු වී ඇති අතර දකුණු පස ඇති අවසාන ඉලක්කම් ශුන්‍යයෙන් පුරවා ඇත. වමට මාරුවීම 2 බලයෙන් ගුණ කිරීමකට සමාන බව ඔබට සටහන් කළ හැකිය. එබැවින් 6 << 1එය සමාන 6 * 2වන අතර 6 << 3සමාන වේ 6 * 8. හොඳ ප්‍රශස්තිකරණ සම්පාදකයෙකු හැකි විට ගුණ කිරීම් මාරුවීම් සමඟ ප්‍රතිස්ථාපනය කරයි.

රවුම් නොවන මාරුව

මේවා රවුම් මාරුව නොවන බව කරුණාවෙන් සලකන්න . මෙම අගය එක් ස්ථානයකින් වමට මාරු කිරීම ( 3,758,096,384 << 1):

11100000 00000000 00000000 00000000

ප්‍රති results ල 3,221,225,472:

11000000 00000000 00000000 00000000

"අවසානයෙන් ඉවතට" මාරු වන ඉලක්කම් නැති වී යයි. එය වටා එතෙන්නේ නැත.


තාර්කික දකුණු මාරුව (>>>)

තාර්කික දකුණු මාරුව යනු වම් මාරුවට සංවාදයයි. බිටු වමට ගෙන යනවා වෙනුවට ඒවා දකුණට ගමන් කරයි. උදාහරණයක් ලෙස, අංක 12 මාරු කිරීම:

00000000 00000000 00000000 00001100

එක් ස්ථානයකින් දකුණට ( 12 >>> 1) අපගේ මුල් 6 නැවත ලබා ගනී:

00000000 00000000 00000000 00000110

එබැවින් දකුණට මාරුවීම 2 බලයෙන් බෙදීමට සමාන බව අපට පෙනේ.

නැතිවූ බිටු නැති වී ඇත

කෙසේ වෙතත්, මාරුවකට "නැතිවූ" බිටු නැවත ලබා ගත නොහැක. උදාහරණයක් ලෙස, අපි මෙම රටාව මාරු කළහොත්:

00111000 00000000 00000000 00000110

වම් ස්ථාන 4 ට ( 939,524,102 << 4), අපට ලැබෙන්නේ 2,147,483,744:

10000000 00000000 00000000 01100000

පසුව ආපසු (939,524,102 << 4) >>> 4මාරුවීමෙන් ( ) අපට ලැබෙන්නේ 134,217,734:

00001000 00000000 00000000 00000110

බිටු නැති වූ පසු අපට අපගේ මුල් වටිනාකම නැවත ලබා ගත නොහැක.


අංක ගණිත දකුණු මාරුව (>>)

අංක ගණිත දකුණු මාරුව හරියටම තාර්කික දකුණු මාරුවට සමානය, ශුන්‍යය සමඟ පෑඩ් කිරීම වෙනුවට, එය වඩාත්ම වැදගත් බිටු සමඟ පෑඩ් කරයි. මෙයට හේතුව වඩාත්ම වැදගත් බිට් සං sign ා බිට් හෝ ධනාත්මක හා negative ණ සංඛ්‍යා වෙන්කර හඳුනා ගන්නා බිට් ය. වඩාත්ම වැදගත් බිටු සමඟ පෑඩ් කිරීමෙන්, අංක ගණිත දකුණු මාරුව සං sign ා සංරක්ෂණය කරයි.

උදාහරණයක් ලෙස, අපි මෙම බිට් රටාව negative ණ සංඛ්‍යාවක් ලෙස අර්ථ දැක්වුවහොත්:

10000000 00000000 00000000 01100000

අපට අංකය -2,147,483,552 ඇත. අංක ගණිත මාරුව (-2,147,483,552 >> 4) සමඟ මෙය නිවැරදි ස්ථාන 4 ට මාරුවීම අපට ලබා දෙනු ඇත:

11111000 00000000 00000000 00000110

හෝ අංකය -134,217,722.

එබැවින් අපගේ negative ණ සංඛ්‍යා වල සං sign ාව තාර්කික දකුණු මාරුවට වඩා අංක ගණිත දකුණු මාරුව භාවිතා කිරීමෙන් අපි ආරක්ෂා කර ඇති බව අපට පෙනේ. නැවත වරක්, 2 බලයෙන් බෙදීම සිදු කරන බව අපට පෙනේ.


306
මෙය ජාවා විශේෂිත පිළිතුරක් බව පිළිතුර වඩාත් පැහැදිලි කළ යුතුය. C / C ++ හෝ C # හි >>> ක්‍රියාකරුවෙකු නොමැත, සහ >> සං sign ාව ප්‍රචාරය කරන්නේද යන්න C / C ++ (ප්‍රධාන විභව ගොචා) හි අර්ථ දක්වා ඇත
මයිකල් බර්

56
සී භාෂාවේ සන්දර්භය තුළ පිළිතුර මුළුමනින්ම වැරදිය. සී හි "අංක ගණිත" සහ "තාර්කික" මාරුවලට අර්ථවත් බෙදීමක් නොමැත. සී හි මාරුවීම් අත්සන් නොකළ අගයන් සහ ධනාත්මක අත්සන් කළ අගයන් මත අපේක්ෂිත පරිදි ක්‍රියා කරයි - ඒවා බිටු මාරු කරයි. Negative ණාත්මක අගයන් මත, දකුණ මාරුව ක්‍රියාත්මක කිරීම අර්ථ දක්වා ඇත (එනම් එය පොදුවේ කරන දේ ගැන කිසිවක් පැවසිය නොහැක), සහ වම් මාරුව සරලවම තහනම්ය - එය නිර්වචනය නොකළ හැසිරීම් ඇති කරයි.
AnT

10
ඕඩ්රි, ගණිතය සහ තාර්කික දකුණ මාරුව අතර වෙනසක් ඇත. C හුදෙක් තේරීම ක්‍රියාත්මක කිරීම අර්ථ දක්වා ඇත. Negative ණ අගයන් මත වම් මාරුව අනිවාර්යයෙන්ම තහනම් නොවේ. 0xff000000 වම් පැත්තට මාරු කරන්න, එවිට ඔබට 0xfe000000 ලැබෙනු ඇත.
ඩෙරෙක් පාක්

16
A good optimizing compiler will substitute shifts for multiplications when possible. කුමන? බිට්ෂිෆ්ට්ස් යනු සී.පී.යූ. හි පහත් මට්ටමේ ක්‍රියාකාරිත්වයට පැමිණෙන විට වේගයෙන් විශාලත්වයේ ඇණවුම් වේ, හොඳ ප්‍රශස්තිකරණ සම්පාදකයෙකු හරියටම ප්‍රතිවිරුද්ධ දේ කරයි, එනම් සාමාන්‍ය බලයන් දෙකක බලයෙන් බිට් මාරුවලට හැරවීම.
මහන්

55
Ah මහන්, ඔබ එය කියවන්නේ මගේ අභිප්‍රායෙනි. X සඳහා Y ආදේශ කිරීම යන්නෙන් අදහස් කරන්නේ X වෙනුවට Y වෙනුවට ආදේශ කිරීමයි. Y යනු X සඳහා ආදේශකයයි. එබැවින් මාරුව යනු ගුණ කිරීම සඳහා ආදේශකයයි.
ඩෙරෙක් පාක්

211

අපට එක බයිට් එකක් ඇතැයි කියමු:

0110110

තනි වම් බිට්ෂිෆ්ට් එකක් යෙදීමෙන් අපට ලැබෙන්නේ:

1101100

වම් කෙළවරේ බිංදුව බයිට් එකෙන් ඉවතට හරවන ලද අතර බයිට් එකේ දකුණු කෙළවරට නව ශුන්‍යයක් එකතු කරන ලදී.

බිටු පෙරළෙන්නේ නැත; ඒවා ඉවතලනු ලැබේ. ඒ කියන්නේ ඔබ 1101100 මාරුවෙන් ඉවත්ව දකුණට මාරුවුවහොත් ඔබට එම ප්‍රති result ලයම නැවත නොලැබෙනු ඇත.

N විසින් වමට මාරුවීම 2 N න් ගුණ කිරීම හා සමාන වේ .

N මගින් දකුණට මාරුවීම (ඔබ භාවිතා කරන්නේ අනුපූරකයක් නම් ) යනු 2 N න් බෙදීම හා වටය ශුන්‍යයට සමාන වේ.

ඔබ 2 ක බලයක් සමඟ වැඩ කරන්නේ නම්, බිට්ෂිෆ්ටිං ඉතා වේගයෙන් ගුණ කිරීම හා බෙදීම සඳහා භාවිතා කළ හැකිය.

උදාහරණයක් ලෙස, පැරණි දිනවල, අපි ක්‍රීඩා සඳහා 13h (320x200 256 වර්ණ) මාදිලිය භාවිතා කළෙමු. 13h ප්‍රකාරයේදී, වීඩියෝ මතකය පික්සෙල් එකකට අනුපිළිවෙලින් සකසා ඇත. එයින් අදහස් කරන්නේ පික්සෙල් සඳහා ස්ථානය ගණනය කිරීම සඳහා, ඔබ පහත ගණිතය භාවිතා කරනු ඇත:

memoryOffset = (row * 320) + column

දැන්, එම දිනය හා වයස අනුව, වේගය ඉතා වැදගත්, එබැවින් අපි මෙම මෙහෙයුම සඳහා බිට්ෂිෆ්ට් භාවිතා කරමු.

කෙසේ වෙතත්, 320 යනු දෙකක බලයක් නොවේ, එබැවින් මෙය වටහා ගැනීම සඳහා එකට එකතු කළ දෙකක බලය කුමක්දැයි සොයා ගත යුතුය 320:

(row * 320) = (row * 256) + (row * 64)

දැන් අපට එය වම් මාරුවලට පරිවර්තනය කළ හැකිය:

(row * 320) = (row << 8) + (row << 6)

අවසාන ප්‍රති result ලය සඳහා:

memoryOffset = ((row << 8) + (row << 6)) + column

දැන් අපට පෙර මෙන් ම ඕෆ්සෙට් එකක් ලැබෙනු ඇත, මිල අධික ගුණ කිරීමේ මෙහෙයුමක් වෙනුවට, අපි බිට්ෂිෆ්ට් දෙක භාවිතා කරමු ... x86 හි එය මේ හා සමාන දෙයක් වනු ඇත (සටහන, මම එකලස් කිරීමෙන් පසු එය සදහටම පැවතුනි (සංස්කාරක සටහන: නිවැරදි කර ඇත යුවළක් වැරදි කර බිටු 32 ක උදාහරණයක් එක් කළේය)):

mov ax, 320; 2 cycles
mul word [row]; 22 CPU Cycles
mov di,ax; 2 cycles
add di, [column]; 2 cycles
; di = [row]*320 + [column]

; 16-bit addressing mode limitations:
; [di] is a valid addressing mode, but [ax] isn't, otherwise we could skip the last mov

එකතුව: පුරාණ CPU හි මෙම වේලාවන් ඇති චක්‍ර 28 ක්.

එදිරිව

mov ax, [row]; 2 cycles
mov di, ax; 2
shl ax, 6;  2
shl di, 8;  2
add di, ax; 2    (320 = 256+64)
add di, [column]; 2
; di = [row]*(256+64) + [column]

එකම පුරාණ CPU මත චක්‍ර 12 ක්.

ඔව්, අපි CPU චක්‍ර 16 ක් කපා දැමීමට මෙය මහන්සි වෙමු.

32 හෝ 64-බිට් ප්‍රකාරයේදී, අනුවාද දෙකම කෙටි හා වේගවත් වේ. ඉන්ටෙල් ස්කයිලේක් වැනි නවීන ක්‍රියා විරහිත ක්‍රියාත්මක කිරීමේ CPUs ( http://agner.org/optimize/ බලන්න ) ඉතා වේගවත් දෘඩාංග ගුණනය (අඩු ප්‍රමාදය සහ ඉහළ ප්‍රති put ල ) ඇත, එබැවින් ලාභය වඩා කුඩා වේ. AMD බුල්ඩෝසර්-පවුල ටිකක් මන්දගාමී වේ, විශේෂයෙන් බිට් 64 ගුණ කිරීම සඳහා. ඉන්ටෙල් සීපීයූ සහ ඒඑම්ඩී රයිසන් මත මාරුවීම් දෙකක් තරමක් අඩු ප්‍රමාදයක් වන නමුත් ගුණනයකට වඩා වැඩි උපදෙස් (අඩු ප්‍රතිදානයකට තුඩු දිය හැකිය):

imul edi, [row], 320    ; 3 cycle latency from [row] being ready
add  edi, [column]      ; 1 cycle latency (from [column] and edi being ready).
; edi = [row]*(256+64) + [column],  in 4 cycles from [row] being ready.

එදිරිව.

mov edi, [row]
shl edi, 6               ; row*64.   1 cycle latency
lea edi, [edi + edi*4]   ; row*(64 + 64*4).  1 cycle latency
add edi, [column]        ; 1 cycle latency from edi and [column] both being ready
; edi = [row]*(256+64) + [column],  in 3 cycles from [row] being ready.

සම්පාදකයින් ඔබ වෙනුවෙන් මෙය කරනු ඇත: ජීසීසී, ක්ලැන්ග් සහ මයික්‍රොසොෆ්ට් විෂුවල් සී ++ සියල්ලම ප්‍රශස්තිකරණය කිරීමේදී ෂිෆ්ට් + ලී භාවිතාreturn 320*row + col; කරන්නේ කෙසේදැයි බලන්න .

මෙහිදී සටහන් කළ යුතු වඩාත්ම සිත්ගන්නා කරුණ නම්, x86 හි මාරුවීම් සහ එකතු කිරීමේ උපදෙස් ( LEA) ඇති අතර එය කුඩා වම් මාරුවීම් කළ හැකි අතර එකවරම එකතු කළ හැකිය add. ARM ඊටත් වඩා බලවත් ය: ඕනෑම උපදේශනයක එක් මෙහෙයුමක් වමට හෝ දකුණට නොමිලේ මාරු කළ හැකිය. එබැවින් බලයේ -2 ලෙස හැඳින්වෙන සම්පාදක-කාල නියතයකින් පරිමාණය කිරීම ගුණනයකට වඩා කාර්යක්ෂම විය හැකිය.


හරි, නවීන දිනවලදී ... දැන් වඩාත් ප්‍රයෝජනවත් දෙයක් වනුයේ බිට් 16 ක පූර්ණ සංඛ්‍යාවක් තුළ බිටු 8 අගයන් දෙකක් ගබඩා කිරීම සඳහා බිට්ෂිෆ්ටිං භාවිතා කිරීමයි. උදාහරණයක් ලෙස, C # හි:

// Byte1: 11110000
// Byte2: 00001111

Int16 value = ((byte)(Byte1 >> 8) | Byte2));

// value = 000011111110000;

C ++ හි, ඔබ structබිට් 8 සාමාජිකයන් දෙදෙනෙකු සමඟ භාවිතා කළේ නම් සම්පාදකයින් ඔබ වෙනුවෙන් මෙය කළ යුතුය , නමුත් ප්‍රායෝගිකව ඔවුන් සැමවිටම එසේ නොවේ.


8
මෙය පුළුල් කිරීම, ඉන්ටෙල් ප්‍රොසෙසර මත (සහ තවත් බොහෝ දේ) මෙය කිරීම වේගවත් වේ: int c, d; c = d << 2; මෙයට වඩා: c = 4 * d; සමහර විට, "c = d << 2 + d << 1" පවා "c = 6 * d" ට වඩා වේගවත් වේ !! ඩොස් යුගයේ ග්‍රැෆික් කාර්යයන් සඳහා මම මෙම උපක්‍රම පුළුල් ලෙස භාවිතා කළෙමි, ඒවා තවදුරටත් එතරම් ප්‍රයෝජනවත් යැයි මම නොසිතමි ...
ජෝ පිනෙඩා

5
@ ජේම්ස්: එතරම් නොවේ, වර්තමානයේ එය වීඩියෝ කාඩ් පතේ ස්ථිරාංග වන අතර ඒ හා සමාන කේත ඇතුළත් වේ, එය CPU වලට වඩා GPU විසින් ක්‍රියාත්මක කළ යුතුය. එබැවින් න්‍යායාත්මකව ඔබට ග්‍රැෆික් කාර්යයන් සඳහා මෙවැනි කේත (හෝ කාර්මාක්ගේ කළු-මැජික් ප්‍රතිලෝම මූල ශ්‍රිතය වැනි) ක්‍රියාත්මක කිරීමට අවශ්‍ය නොවේ :-)
ජෝ පිනෙඩා

3
@JoePineda @james සම්පාදක ලේඛකයින් අනිවාර්යයෙන්ම ඒවා භාවිතා කරයි. ඔබ ලියන්නේ නම් ඔබට c=4*dමාරුවක් ලැබෙනු ඇත. ඔබ ලියන්නේ k = (n<0)නම් එය මාරුවීම් වලින් ද කළ හැකිය: k = (n>>31)&1ශාඛාවක් වළක්වා ගැනීමට. බොටම් ලයින්, සම්පාදකයින්ගේ දක්ෂතාවයේ මෙම වැඩිදියුණු කිරීම යනු සී කේතයේ මෙම උපක්‍රම භාවිතා කිරීම දැන් අනවශ්‍ය වන අතර ඒවා කියවීමේ හැකියාව සහ අතේ ගෙන යා හැකි බව පාවා දෙයි. ඔබ ලියන්නේ නම් ඒවා දැන ගැනීම තවමත් ඉතා හොඳයි. උදා: SSE දෛශික කේතය; හෝ ඔබට එය වේගයෙන් අවශ්‍ය වන ඕනෑම තත්වයක් සහ සම්පාදකයා භාවිතා නොකරන උපක්‍රමයක් ඇත (උදා: GPU කේතය).
ග්‍රෙගෝ

2
තවත් හොඳ උදාහරණයක්: ඉතා පොදු දෙයක් if(x >= 1 && x <= 9)ලෙස ඉටු කල හැකි if( (unsigned)(x-1) <=(unsigned)(9-1)) එකක්, කොන්දේසි පරීක්ෂණ දෙකක් වෙනස් විශාල වේගය වාසිය විය හැක; විශේෂයෙන් එය අතු වෙනුවට පුරෝකථනය කිරීමට ඉඩ දෙන විට. මීට වසර 10 කට පෙර මම මෙය වසර ගණනාවක් තිස්සේ භාවිතා කළෙමි. සම්පාදකයාට ඔබ වෙනුවෙන් පරිවර්තනයක් කළ නොහැකි සමාන අවස්ථා ඇති බැවින් දැන ගැනීම තවමත් හොඳයි. නැතහොත් ඔබ සම්පාදකයෙකු මත වැඩ කරන්නේ නම්.
ග්‍රෙගෝ

3
ඔබේ "බයිට්" බිටු 7 ක් පමණක් වීමට හේතුවක් තිබේද?
මේසන් වොට්මෝග්

104

බිට් මාරුව ඇතුළුව බිට්වයිස් මෙහෙයුම් පහත් මට්ටමේ දෘඩාංග හෝ කාවැද්දූ වැඩසටහන්කරණය සඳහා මූලික වේ. ඔබ උපාංගයක් සඳහා පිරිවිතරයක් හෝ සමහර ද්විමය ගොනු ආකෘති කියවා බැලුවහොත්, ඔබට උනන්දුවක් දක්වන විවිධ අගයන් අඩංගු බයිට්, වචන සහ ද්වාරයන් බයිට් නොවන පෙලගැසී ඇති බිට්ෆීල්ඩ් වලට කැඩී ඇත. කියවීම / ලිවීම සඳහා මෙම බිට්-ක්ෂේත්‍ර වෙත ප්‍රවේශ වීම වඩාත් පොදු භාවිතයකි.

ග්‍රැෆික් ක්‍රමලේඛනයේ සරල සැබෑ උදාහරණයක් නම් බිට් 16 පික්සෙල් පහත පරිදි නිරූපණය වේ:

  bit | 15| 14| 13| 12| 11| 10| 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1  | 0 |
      |       Blue        |         Green         |       Red          |

හරිත අගය ලබා ගැනීම සඳහා ඔබ මෙය කරනු ඇත:

 #define GREEN_MASK  0x7E0
 #define GREEN_OFFSET  5

 // Read green
 uint16_t green = (pixel & GREEN_MASK) >> GREEN_OFFSET;

පැහැදිලි කිරීම

හරිත පමණක් වටිනාකම ලබා ගැනීම සඳහා, ඕෆ්සෙට් 5 සිට ආරම්භ වී 10 ට (එනම් බිටු 6 ක් දිග) අවසන් වීමට නම්, ඔබ (බිට්) ආවරණයක් භාවිතා කළ යුතුය, එය බිට් 16 පික්සෙල්ට එරෙහිව යොදන විට, එය ලැබෙනු ඇත. අපි උනන්දු වන්නේ බිටු පමණි.

#define GREEN_MASK  0x7E0

සුදුසු ආවරණ 0x7E0 වන අතර ද්විමය වශයෙන් 0000011111100000 (එය 2016 දශමයෙන්) වේ.

uint16_t green = (pixel & GREEN_MASK) ...;

වෙස් මුහුණක් යෙදීම සඳහා, ඔබ AND ක්‍රියාකරු (&) භාවිතා කරයි.

uint16_t green = (pixel & GREEN_MASK) >> GREEN_OFFSET;

වෙස්මුහුණ යෙදීමෙන් පසු, ඔබ අවසන් වන්නේ 16-බිට් අංකයකින් වන අතර එය ඇත්ත වශයෙන්ම බිට් 11 ක් පමණක් වන අතර එහි MSB 11 වන බිට් එකේ ඇත. කොළ පාට ඇත්ත වශයෙන්ම බිටු 6 ක් පමණක් වන බැවින් නිවැරදි මාරුවක් (11 - 6 = 5) භාවිතා කරමින් එය පරිමාණයට අඩු කළ යුතුය, එබැවින් 5 ඕෆ්සෙට් ( #define GREEN_OFFSET 5) ලෙස භාවිතා කිරීම .

වේගවත් ගුණ කිරීම සහ 2 බලයෙන් බෙදීම සඳහා බිට් මාරුව භාවිතා කිරීම ද පොදු ය:

 i <<= x;  // i *= 2^x;
 i >>= y;  // i /= 2^y;

1
0x7e0 යනු 11111100000 ට සමාන වන අතර එය 2016 දශමයෙන් වේ.
සහීඩ්

50

බිට් ආවරණ සහ මාරුව

බිට් මාරුව බොහෝ විට පහත් මට්ටමේ ග්‍රැෆික් වැඩසටහන් වල භාවිතා වේ. උදාහරණයක් ලෙස, ලබා දී ඇති පික්සල් වර්ණ අගය බිට් 32 වචනයකින් කේතනය කර ඇත.

 Pixel-Color Value in Hex:    B9B9B900
 Pixel-Color Value in Binary: 10111001  10111001  10111001  00000000

වඩා හොඳ අවබෝධයක් සඳහා, කුමන වර්ණ කොටස නියෝජනය කරන්නේ කුමන කොටස් සමඟ ලේබල් කරන ලද එකම ද්විමය අගයයි.

                                 Red     Green     Blue       Alpha
 Pixel-Color Value in Binary: 10111001  10111001  10111001  00000000

උදාහරණයක් ලෙස මෙම පික්සෙල් වර්ණයෙහි හරිත අගය ලබා ගැනීමට අපට අවශ්‍ය යැයි කියමු. වෙස්මුහුණු සහ මාරු කිරීමෙන් අපට පහසුවෙන් එම අගය ලබා ගත හැකිය .

අපගේ වෙස් මුහුණ:

                  Red      Green      Blue      Alpha
 color :        10111001  10111001  10111001  00000000
 green_mask  :  00000000  11111111  00000000  00000000

 masked_color = color & green_mask

 masked_color:  00000000  10111001  00000000  00000000

තාර්කික &ක්‍රියාකරු සහතික කරන්නේ ආවරණ 1 හි ඇති අගයන් පමණක් තබා ඇති බවයි. අප දැන් කළ යුතු අවසාන දෙය නම්, එම බිටු සියල්ලම ස්ථාන 16 කින් දකුණට මාරු කිරීමෙන් නිවැරදි සංඛ්‍යා පූර්ණ අගය ලබා ගැනීමයි (තාර්කික දකුණු මාරුව) .

 green_value = masked_color >>> 16

සහ, පික්සෙල් වර්ණයෙහි හරිත ප්‍රමාණය නිරූපණය කරන පූර්ණ සංඛ්‍යාවක් අප සතුව ඇත:

 Pixels-Green Value in Hex:     000000B9
 Pixels-Green Value in Binary:  00000000 00000000 00000000 10111001
 Pixels-Green Value in Decimal: 185

මෙම බොහෝ විට ප්රතිරූපයක් ආකෘති සංකේතවත් හෝ ප්රහේලිකාව ලිහා සඳහා භාවිතා කරනු ඇත jpg, pngආදිය,


ඔබේ මුල් පිටපත වාත්තු කිරීම පහසු නොවේද, 32bit cl_uint, cl_uchar4 වැනි දෙයක් ලෙස ඔබට අවශ්‍ය බයිට් එකට කෙලින්ම * .s2 ලෙස ප්‍රවේශ වන්න?
ඩේවිඩ් එච් පැරි

27

එක් කරුණක් නම් පහත දැක්වෙන්නේ ක්‍රියාත්මක කිරීම මත රඳා පවතින බවය (ANSI ප්‍රමිතියට අනුව):

char x = -1;
x >> 1;

x දැන් 127 (01111111) හෝ තවමත් -1 (11111111) විය හැකිය.

ප්රායෝගිකව, එය සාමාන්යයෙන් දෙවැන්නයි.


4
මා එය නිවැරදිව සිහිපත් කළහොත්, ANSI C ප්‍රමිතිය පැහැදිලිවම පවසන්නේ මෙය ක්‍රියාත්මක කිරීම මත රඳා පවතින බවය, එබැවින් ඔබේ කේතයේ අත්සන් කළ පූර්ණ සංඛ්‍යා නිවැරදිව මාරුවීමට අවශ්‍ය නම් එය ක්‍රියාත්මක වන්නේ කෙසේදැයි බැලීමට ඔබේ සම්පාදකයාගේ ලේඛන පරීක්ෂා කළ යුතුය.
ජෝ පිනෙඩා

ඔව්, මට අවශ්‍ය වූයේ ANSI ප්‍රමිතියම එසේ පැවසීමයි, එය වෙළෙන්දෝ හුදෙක් ප්‍රමිතිය අනුගමනය නොකරන හෝ ප්‍රමිතිය මෙම අංශු නඩුව ගැන කිසිවක් නොකියන අවස්ථාවක් නොවේ.
ජෝ පිනෙඩා

22

මම ලියන්නේ ඉඟි සහ උපක්‍රම පමණි. පරීක්ෂණ සහ විභාග සඳහා එය ප්‍රයෝජනවත් විය හැකිය.

  1. n = n*2: n = n<<1
  2. n = n/2: n = n>>1
  3. N යනු 2 හි බලය දැයි පරීක්ෂා කිරීම (1,2,4,8, ...): පරීක්ෂා කරන්න !(n & (n-1))
  4. ලබා ගැනීම x වැනි ටිකක් n:n |= (1 << x)
  5. X ඉරට්ටේ හෝ අමුතු දැයි පරීක්ෂා කිරීම: x&1 == 0(ඉරට්ටේ)
  6. මෙම ටොගල් කරන්න n වන x හි ටිකක්:x ^ (1<<n)

මේ වන විට ඔබ දන්නා තවත් කිහිපයක් තිබිය යුතුද?
ryyker

yryyker මම තවත් කිහිපයක් එකතු කර ඇත්තෙමි. මම එය දිගටම යාවත්කාලීන කිරීමට උත්සාහ කරමි :)
රවී ප්‍රකාශ්

X සහ n 0 සුචිගත කර තිබේද?
reggaeguitar

දැන්වීම 5: එය negative ණ සංඛ්‍යාවක් නම් කුමක් කළ යුතුද?
පීටර් මෝර්ටෙන්සන්

ඉතින්, ද්විමය වශයෙන් 2 දශමයෙන් 10 ක් යැයි නිගමනය කළ හැකිද? බිට් මාරුව යනු දශමයෙන් තවත් අංකයක් පිටුපස තවත් අංකයක් එකතු කිරීම හෝ ආදේශ කිරීම හා සමානද?
විලී සැට්රියෝ නුග්‍රෝහෝ

8

ජාවා ක්‍රියාත්මක කිරීමේදී, මාරුවීමට ඇති බිට් ගණන ප්‍රභවයේ ප්‍රමාණය අනුව වෙනස් කර ඇති බව සලකන්න.

උදාහරණයක් වශයෙන්:

(long) 4 >> 65

සමාන වේ 2. බිටු 65 වතාවක් දකුණට මාරුවීම සියල්ල ශුන්‍ය වනු ඇතැයි ඔබ අපේක්ෂා කළ හැකිය, නමුත් එය ඇත්ත වශයෙන්ම සමාන වන්නේ:

(long) 4 >> (65 % 64)

<<, >>, සහ >>> සඳහා මෙය සත්‍ය වේ. මම එය වෙනත් භාෂාවලින් අත්හදා බැලුවේ නැත.


හහ්, රසවත්! සී හි මෙය තාක්ෂණික වශයෙන් නිර්වචනය නොකළ හැසිරීමකි . gcc 5.4.0අනතුරු ඇඟවීමක් කරයි, නමුත් 25 >> 65 සඳහා ලබා දෙයි ; එසේම.
pizzapants184

2

පයිතන් හි සමහර ප්‍රයෝජනවත් බිට් මෙහෙයුම් / හැසිරවීම්.

මම රවී ප්‍රකාශ්ගේ පිළිතුර පයිතන්හි ක්‍රියාත්මක කළා.

# Basic bit operations
# Integer to binary
print(bin(10))

# Binary to integer
print(int('1010', 2))

# Multiplying x with 2 .... x**2 == x << 1
print(200 << 1)

# Dividing x with 2 .... x/2 == x >> 1
print(200 >> 1)

# Modulo x with 2 .... x % 2 == x & 1
if 20 & 1 == 0:
    print("20 is a even number")

# Check if n is power of 2: check !(n & (n-1))
print(not(33 & (33-1)))

# Getting xth bit of n: (n >> x) & 1
print((10 >> 2) & 1) # Bin of 10 == 1010 and second bit is 0

# Toggle nth bit of x : x^(1 << n)
# take bin(10) == 1010 and toggling second bit in bin(10) we get 1110 === bin(14)
print(10^(1 << 2))

2

බිට්වේස් ක්‍රියාකරුවන් භාවිතා කරනුයේ මෙහෙයුම් ටිකක් මට්ටමින් සිදු කිරීමට හෝ විවිධ ආකාරවලින් බිටු හැසිරවීමට ය. බිට්වේස් මෙහෙයුම් වඩා වේගවත් බව සොයාගෙන ඇති අතර සමහර විට එය වැඩසටහනක කාර්යක්ෂමතාව වැඩි දියුණු කිරීමට භාවිතා කරයි. මූලික වශයෙන්, බිට්වයිස් ක්‍රියාකරුවන් පූර්ණ සංඛ්‍යා වර්ග සඳහා යෙදිය හැකිය: දිගු , int , කෙටි , වරහන් සහ බයිට් .

බිට්වයිස් මාරුව ක්‍රියාකරුවන්

ඒවා වම් මාරුව සහ දකුණු මාරුව යනුවෙන් කොටස් දෙකකට වර්ග කර ඇත.

  • වම් මාරුව (<<): වම් මාරුව ක්‍රියාකරු, වටිනාකමින් යුත් සියලු බිටු වමට නිශ්චිත වාර ගණනක් මාරු කරයි. වාක්‍ය ඛණ්ඩය: අගය << අංකය. මෙහි අංක මඟින් අගයෙහි අගය වමේ සිට මාරුවිය යුතු ස්ථානය දක්වා ඇත. එනම්, << නිශ්චිත අගයේ ඇති සියලුම බිටු වම් පසින් චලනය කරන්නේ සංඛ්‍යා මගින් නිශ්චිතව දක්වා ඇති බිට් ස්ථාන ගණනෙනි. වම්පස ඇති සෑම මාරුවක් සඳහාම, ඉහළ ඇණවුම් බිට් එක මාරු කරනු ලැබේ (සහ නොසලකා හරිනු ලැබේ / නැති වී යයි), සහ ශුන්‍යය දකුණට ගෙන එනු ලැබේ. මෙයින් අදහස් කරන්නේ බිට් 32 සම්පාදකය සඳහා වම් මාරුවක් යොදන විට, බිටු 31 පසු ගිය පසු මාරු වූ පසු බිටු නැති වන බවයි. සම්පාදකයා බිට් 64 ක් නම්, බිට් 63 න් පසු බිටු නැති වේ.

රූප විස්තරය මෙහි ඇතුළත් කරන්න

නිමැවුම්: 6 , මෙහි 3 හි ද්විමය නිරූපණය 0 ... 0011 (බිටු 32 පද්ධතිය සලකා බලයි) එබැවින් එය එක් වරක් මාරු කළ විට ප්‍රමුඛ ශුන්‍යය නොසලකා හරිනු ලැබේ / නැති වී යයි, ඉතිරි බිටු 31 වමට මාරු වේ. තවද ශුන්‍යය අවසානයේ එකතු වේ. එබැවින් එය 0 ... 0110 බවට පත් විය, මෙම සංඛ්‍යාවේ දශම නිරූපණය 6 කි.

  • Negative ණ සංඛ්‍යාවක් සම්බන්ධයෙන්:

සෘණ අංකය සඳහා කේතය.

ප්‍රතිදානය: -2 , ජාවා negative ණ සංඛ්‍යාවේ 2 හි අනුපූරකය මගින් නිරූපණය කෙරේ. SO, -1 නිරූපණය කරන්නේ 2 ^ 32-1 වන අතර එය 1 .... 11 ට සමාන වේ (32-බිට් පද්ධතිය සැලකිල්ලට ගනිමින්). එක් වරක් මාරු කළ විට ප්‍රමුඛ බිට් නොසලකා හරිනු ලැබේ / නැති වේ. ඉතිරි බිටු 31 වමට මාරු වන අතර අන්තිමේදී ශුන්‍යය එකතු වේ. එබැවින් එය 11 ... 10 බවට පත්වන අතර එහි දශමයට සමාන -2 වේ. ඉතින්, මම හිතන්නේ ඔබට වම් මාරුව සහ එහි ක්‍රියාකාරිත්වය පිළිබඳ ප්‍රමාණවත් දැනුමක් ලැබෙනු ඇත.

  • දකුණු මාරුව (>>): නිවැරදි මාරුව ක්‍රියාකරු, වටිනාකමින් යුත් සියලු බිටු නිශ්චිත වේලාවට දකුණට මාරු කරයි. වාක්‍ය ඛණ්ඩය: අගය >> අංකය, අගය මඟින් අගයෙහි අගය දකුණට මාරුවීම සඳහා ස්ථාන ගණන නියම කරයි. එනම්, >> බිටු සියල්ලම දකුණේ නිශ්චිත අගයේ චලනය / මාරු කිරීම අංක මගින් නිශ්චිතව දක්වා ඇති බිට් ස්ථාන ගණන. පහත කේත කැබැල්ල 35 හි අගය ස්ථාන දෙකකින් දකුණට මාරු කරයි:

රූප විස්තරය මෙහි ඇතුළත් කරන්න

නිමැවුම්: 8 , 32-බිට් පද්ධතියක 35 හි ද්විමය නිරූපණය 00 ... 00100011, එබැවින් අපි එය දෙවරක් හරවන විට පළමු ප්‍රමුඛ බිටු 30 ක් දකුණු පැත්තට ගෙනයනු ලැබේ / දකුණට මාරු වේ. බිටු නැතිවී / නොසලකා හරින අතර ප්‍රමුඛ බිටු වල ශුන්‍ය දෙකක් එකතු වේ. ඉතින්, එය 00 .... 00001000 බවට පත්වේ, මෙම ද්විමය නිරූපණයේ දශමයට සමාන 8 වේ. නැතහොත් මෙම පහත කේතයේ ප්‍රතිදානය සොයා ගැනීමට සරල ගණිතමය උපක්‍රමයක් ඇත: මෙය සාමාන්‍යකරණය කිරීම සඳහා අපට එය පැවසිය හැකිය, x >> y = මහල (x / pow (2, y)). ඉහත උදාහරණය සලකා බලන්න, x = 35 සහ y = 2 එසේ නම්, 35/2 ^ 2 = 8.75 සහ අපි බිම් අගය ගත්තොත් පිළිතුර 8 වේ.

රූප විස්තරය මෙහි ඇතුළත් කරන්න

ප්‍රතිදානය:

රූප විස්තරය මෙහි ඇතුළත් කරන්න

නමුත් y හි කුඩා අගයන් සඳහා මෙම උපක්‍රමය කදිම බව මතක තබා ගන්න. ඔබ y හි විශාල අගයන් ගත්තොත් එය ඔබට වැරදි ප්‍රතිදානයක් ලබා දෙයි.

  • Negative ණ සංඛ්‍යාවක් සම්බන්ධයෙන්: negative ණ සංඛ්‍යා නිසා දකුණු මාරුව ක්‍රියාකරු අත්සන් කර අත්සන් නොකළ ආකාර දෙකකින් ක්‍රියා කරයි. අත්සන් කරන ලද දකුණු මාරුව ක්‍රියාකරු (>>), ධනාත්මක සංඛ්‍යාවක් නම්, එය ප්‍රමුඛ බිටු 0 සමඟ පුරවයි. Negative ණ සංඛ්‍යාවක් නම්, එය ප්‍රමුඛ බිටු 1 සමඟ පුරවයි. ලකුණ තබා ගැනීමට. මෙය 'සං sign ා දිගුව' ලෙස හැඳින්වේ.

රූප විස්තරය මෙහි ඇතුළත් කරන්න

ප්‍රතිදානය: -5 , මම ඉහත විස්තර කළ පරිදි සම්පාදකයාගේ negative ණ අගය 2 හි අනුපූරකය ලෙස ගබඩා කරයි. ඉතින්, -10 2 ^ 32-10 ලෙසත් ද්විමය නිරූපණයෙන් 32-බිට් පද්ධති 11 .... 0110 ලෙසත් නිරූපණය කෙරේ. අපි එක් වරක් මාරු කරන විට / චලනය කරන විට පළමු ප්‍රමුඛ බිටු 31 දකුණු පැත්තේ මාරුවී ඇති අතර පහත් ඇණවුමේ බිට් නැති වී / නොසලකා හරිනු ලැබේ. ඉතින්, එය 11 ... 0011 බවට පත්වන අතර මෙම සංඛ්‍යාවේ දශම නිරූපණය -5 (අංකයේ ලකුණ මා දන්නේ කෙසේද? ප්‍රමුඛ බිට් 1 නිසා). ඔබ -1 දකුණට මාරුවුවහොත්, ප්‍රති result ලය සැමවිටම -1 ලෙස පවතින්නේ සං sign ා දිගුව ඉහළ පෙළේ බිටු තුළට තවත් ඒවා ගෙන ඒම නිසාය.

  • අත්සන් නොකළ දකුණු මාරුව (>>>): මෙම ක්‍රියාකරු ද බිටු දකුණට මාරු කරයි. අත්සන් කළ සහ අත්සන් නොකළ අතර වෙනස වන්නේ negative ණ නම් අංක 1 සමඟ ප්‍රමුඛ බිටු 1 ක් පුරවන අතර කලින් අවස්ථා දෙකෙහිම ශුන්‍යය පුරවයි. අත්සන් කරන ලද දකුණු මාරුව ක්‍රියාකරු විසින් අපේක්ෂිත ප්‍රතිදානය ලබා ගන්නේ නම් අපට අත්සන් නොකළ නිවැරදි ක්‍රියාකාරිත්වය අවශ්‍ය වන්නේ ඇයිද යන ප්‍රශ්නය දැන් පැන නගී. උදාහරණයකින් මෙය තේරුම් ගන්න, ඔබ සංඛ්‍යාත්මක අගයක් නියෝජනය නොකරන දෙයක් මාරු කරන්නේ නම්, සං sign ා දිගුව සිදුවීමට ඔබට අවශ්‍ය නොවනු ඇත. ඔබ පික්සල් මත පදනම් වූ අගයන් සහ ග්‍රැෆික්ස් සමඟ වැඩ කරන විට මෙම තත්වය පොදු වේ. මෙම අවස්ථා වලදී, සාමාන්‍යයෙන් ශුන්‍යය ආරම්භක අගය කුමක් වුවත් ඉහළ ඇණවුමකට මාරු කිරීමට ඔබට අවශ්‍ය වනු ඇත.

රූප විස්තරය මෙහි ඇතුළත් කරන්න

ප්‍රතිදානය: 2147483647 , මන්ද යත් -2 බිට් 32 පද්ධතියක 11 ... 10 ලෙස නිරූපණය වන බැවිනි. අපි බිට් එක එකින් එක මාරු කරන විට, පළමු ප්‍රමුඛ බිට් 31 චලනය කර / දකුණට මාරුවෙන අතර පහත් ඇණවුමේ බිට් නැති වී / නොසලකා හරිනු ලබන අතර ශුන්‍යය ප්‍රමුඛ බිට් එකට එකතු වේ. ඉතින්, එය 011 ... 1111 (2 ^ 31-1) බවට පත්වන අතර එහි දශමයට සමාන 2147483647 වේ.


-3

වින්ඩෝස් වේදිකාවේ ඇත්තේ PHP හි බිට් 32 අනුවාදයක් පමණක් බව මතක තබා ගන්න.

උදාහරණයක් ලෙස ඔබ බිටු 31 ට වඩා මාරුව << හෝ >> නම්, ප්‍රති results ල බලාපොරොත්තු විය නොහැක. සාමාන්‍යයෙන් ශුන්‍යයන් වෙනුවට මුල් අංකය නැවත ලැබෙනු ඇති අතර එය ඇත්තෙන්ම උපක්‍රමශීලී දෝෂයකි.

ඇත්ත වශයෙන්ම ඔබ PHP (යුනික්ස්) හි බිට් 64 අනුවාදයක් භාවිතා කරන්නේ නම්, ඔබ බිට් 63 ට වඩා මාරුවීමෙන් වැළකී සිටිය යුතුය. කෙසේ වෙතත්, උදාහරණයක් ලෙස, MySQL 64-bit BIGINT භාවිතා කරයි, එබැවින් කිසිදු අනුකූලතා ගැටළුවක් නොවිය යුතුය.

යාවත්කාලීන කිරීම: PHP 7 වින්ඩෝස් වෙතින්, PHP බිල්ඩ්ස් හට සම්පූර්ණ බිට් 64 පූර්ණ සංඛ්‍යා භාවිතා කළ හැකිය: පූර්ණ සංඛ්‍යාවක ප්‍රමාණය වේදිකාව මත රඳා පවතී, නමුත් උපරිම අගය බිලියන දෙකක පමණ සාමාන්‍ය අගය වුවද (එය බිට් 32 අත්සන් කර ඇත). 64-බිට් වේදිකාවල සාමාන්‍යයෙන් උපරිම අගය 9E18 පමණ වේ, PHP 7 ට පෙර වින්ඩෝස් හැර, එය සෑම විටම බිට් 32 ක් විය.

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.