বিটওয়াস শিফট (বিট শিফট) অপারেটরগুলি কী কী এবং তারা কীভাবে কাজ করে?


1380

আমি আমার অতিরিক্ত সময়ে সি শিখার চেষ্টা করছিলাম, এবং অন্যান্য ভাষা (সি #, জাভা ইত্যাদি) একই ধারণা (এবং প্রায়শই একই অপারেটর) থাকে ...

মূল স্তরে, আমি কি হতাশ করছি, কি করে বিট-নাড়াচাড়া ( <<, >>, >>>) না, কি সমস্যা এটা সাহায্য করতে পারেন সমাধান, এবং কি gotchas প্রায় মোড় লুকিয়ে থাকা? অন্য কথায়, এর সমস্ত সদ্ব্যবহারে কিছুটা স্থানান্তরিত করার জন্য এক নিখুঁত শিক্ষানবিশ গাইড।


2
কার্যকরী বা অ-কার্যকরী কেসগুলিতে আপনি 3 জিএল-তে বিট শিফটিং ব্যবহার করবেন।
ট্রয় ডিমনব্রুন

14
এই উত্তরগুলি পড়ার পরে আপনি এই লিঙ্কগুলি দেখতে চাইতে পারেন: গ্রাফিক্স.স্তানফোর্ড.ইডু / এসেন্ডার
নখর

1
এটি লক্ষ করা গুরুত্বপূর্ণ যে বিট-শিফটিং কম্পিউটারগুলির পক্ষে করা অত্যন্ত সহজ এবং দ্রুত। আপনার প্রোগ্রামে বিট-শিফটিং ব্যবহারের উপায়গুলি সন্ধান করে, আপনি মেমরির ব্যবহার এবং প্রয়োগের সময়গুলি হ্রাস করতে পারেন।
হোয়াইটম্যান

@ হইটম্যান: তবে নোট করুন যে ভাল সংকলকগণ ইতিমধ্যে এর মধ্যে অনেক কৌশল জানেন এবং এটি উপলব্ধি করে কোথায় তা স্বীকৃতি দেওয়ার ক্ষেত্রে আরও ভাল।
সেবাস্তিয়ান মাচ

উত্তর:


1712

বিট শিফটিং অপারেটররা ঠিক তাদের নামটি বোঝায় do তারা বিট শিফট। বিভিন্ন শিফট অপারেটরগুলির একটি সংক্ষিপ্ত (বা না-তাই সংক্ষিপ্ত) পরিচয় এখানে।

অপারেটররা

  • >> পাটিগণিত (বা স্বাক্ষরিত) ডান শিফট অপারেটর।
  • >>> লজিকাল (বা স্বাক্ষরবিহীন) ডান শিফট অপারেটর।
  • << বাম শিফট অপারেটর এবং লজিকাল এবং পাটিগণিত উভয় বদল প্রয়োজন meets

এই অপারেটরদের সকল পূর্ণসংখ্যা মান প্রয়োগ করা যেতে পারে ( int, long, সম্ভবত shortএবং byteবা char)। কিছু ভাষায়, শিফট অপারেটরগুলিকে অপারেটরকে intস্বয়ংক্রিয়ভাবে আকার হিসাবে পরিবর্তিত করে তুলনায় ছোট কোনও ডেটাটাইপগুলিতে প্রয়োগ করা হয় int

দ্রষ্টব্য যে <<<কোনও অপারেটর নয়, কারণ এটি অনর্থক হবে।

এছাড়াও লক্ষ করুন যে সি এবং সি ++ ডান শিফট অপারেটরগুলির মধ্যে পার্থক্য করে না । এগুলি কেবল >>অপারেটর সরবরাহ করে এবং ডান-শিফটিং আচরণ হ'ল স্বাক্ষরিত ধরণের জন্য নির্ধারিত বাস্তবায়ন। উত্তরটির বাকি অংশগুলি সি # / জাভা অপারেটরগুলি ব্যবহার করে।

(সমস্ত মূলধারার সি এবং সি ++ জিসিসি এবং ঝনঝন / LLVM সহ বাস্তবায়নের সালে >>স্বাক্ষরিত ধরনের গাণিতিক কিছু কোডটির এই অনুমান, কিন্তু এটা কিছু মান নিশ্চয়তা নয় এটা না।। Undefined , যদিও; মান এটা এক সংজ্ঞায়িত করতে বাস্তবায়নের প্রয়োজন উপায় বা অন্য কোনও। তবে, নেতিবাচক স্বাক্ষরযুক্ত সংখ্যার বাম শিফ্টগুলি হ'ল সংজ্ঞায়িত আচরণ (স্বাক্ষরিত পূর্ণসংখ্যার ওভারফ্লো) So সুতরাং আপনার গাণিতিক ডান শিফ্ট না লাগলে সাধারণত স্বাক্ষরবিহীন ধরণের সাথে আপনার বিট-শিফটিং করা ভাল idea


বাম শিফ্ট (<<)

পূর্ণসংখ্যা বিটগুলির একটি সিরিজ হিসাবে, মেমরিতে সঞ্চয় করা হয়। উদাহরণস্বরূপ, 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

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

একবার বিটস হারিয়ে গেলে আমরা আমাদের আসল মানটি ফিরে পেতে পারি না।


পাটিগণিত ডান শিফট (>>)

পাটিগণিত ডান শিফট হ'ল লজিকাল রাইট শিফ্টের মতো, শূন্যের সাথে প্যাডিংয়ের পরিবর্তে, এটি সর্বাধিক উল্লেখযোগ্য বিট দিয়ে প্যাড করে। এটি কারণ সর্বাধিক উল্লেখযোগ্য বিট হ'ল সাইন বিট, বা বিট যা ইতিবাচক এবং negativeণাত্মক সংখ্যার পার্থক্য করে। সর্বাধিক উল্লেখযোগ্য বিটের সাথে প্যাডিংয়ের মাধ্যমে, গাণিতিক ডান শিফটটি সাইন-সংরক্ষণ করা।

উদাহরণস্বরূপ, আমরা যদি এই বিট প্যাটার্নটিকে negativeণাত্মক সংখ্যা হিসাবে ব্যাখ্যা করি:

10000000 00000000 00000000 01100000

আমাদের সংখ্যাটি -2,147,483,552 রয়েছে। পাটিগণিত শিফট (-2,147,483,552 >> 4) দিয়ে ডান 4 পজিশনে এ স্থানান্তর করা আমাদের দেবে:

11111000 00000000 00000000 00000110

বা নম্বর -134,217,722।

সুতরাং আমরা দেখতে পাচ্ছি যে আমরা লজিকাল ডান শিফ্টের পরিবর্তে পাটিগণিত ডান শিফটটি ব্যবহার করে আমাদের নেতিবাচক সংখ্যার চিহ্নটি সংরক্ষণ করেছি। এবং আবারও, আমরা দেখতে পাচ্ছি যে আমরা 2 এর ক্ষমতা দিয়ে বিভাগ সম্পাদন করছি।


303
উত্তরটি আরও স্পষ্ট করে তুলবে যে এটি একটি জাভা-নির্দিষ্ট উত্তর। সি / সি ++ বা সি # তে কোনও >>> অপারেটর নেই, এবং সাইনটি প্রচার করে কিনা তা >> সি / সি ++ (একটি প্রধান সম্ভাব্য গ্যাচা) এ সংজ্ঞায়িত বাস্তবায়ন কিনা
মাইকেল

55
উত্তর সি ভাষার প্রসঙ্গে সম্পূর্ণ ভুল। সি তে "গাণিতিক" এবং "যৌক্তিক" শিফটে কোনও অর্থবহ বিভাজন নেই সি তে শিফটগুলি স্বাক্ষরযুক্ত স্বীকৃত মান এবং ইতিবাচক স্বাক্ষরিত মানগুলিতে প্রত্যাশা অনুযায়ী কাজ করে - এগুলি কেবল বিটগুলিকে শিফট করে। নেতিবাচক মানগুলিতে ডান-শিফটকে বাস্তবায়ন সংজ্ঞায়িত করা হয় (যেমন এটি সাধারণভাবে কী করে সে সম্পর্কে কিছুই বলা যায় না), এবং বাম-শিফটটি কেবল নিষিদ্ধ - এটি অপরিবর্তিত আচরণ তৈরি করে।
এএনটি

10
অড্রে, পাটিগণিত এবং লজিকাল ডান স্থানান্তর মধ্যে অবশ্যই একটি পার্থক্য আছে। সি কেবল পছন্দটি প্রয়োগের সংজ্ঞা দেয় leaves এবং নেতিবাচক মানগুলিতে বাম স্থানান্তর অবশ্যই নিষিদ্ধ নয়। 0xff000000 বাম এক বিট স্থানান্তর করুন এবং আপনি 0xfe000000 পাবেন।
ডেরেক পার্ক

16
A good optimizing compiler will substitute shifts for multiplications when possible. কি? বিটিশিফ্টগুলি তাত্ক্ষণিকতার অর্ডার হয় যখন এটি সিপিইউর নিম্ন স্তরের ক্রিয়াকলাপে নেমে আসে, একটি ভাল অপ্টিমাইজিং সংকলক হুবহু বিপরীতটি করে, অর্থাত্ দুটি বিটের শিফটে সাধারণ গুণকে বিট শিফটে পরিণত করে।
মাহন

55
@ মাহান, আপনি আমার উদ্দেশ্য থেকে এটি পিছনের দিকে পড়ছেন। X এর জন্য Y এর পরিবর্তে X এর পরিবর্তে Y এর বিকল্প করা উচিত Y X এর বিকল্প So তাই শিফটটি গুণণের বিকল্প lic
ডেরেক পার্ক

208

ধরা যাক আমাদের একক বাইট রয়েছে:

0110110

একটি একক বাম বিটশিট প্রয়োগ করা আমাদের পায়:

1101100

বাম দিকের শূন্যটি বাইটের বাইরে সরিয়ে নেওয়া হয়েছিল এবং বাইটের ডান প্রান্তে একটি নতুন শূন্য যুক্ত করা হয়েছিল।

বিটগুলি রোলওভার করে না; তারা ফেলে দেওয়া হয়। এর অর্থ আপনি যদি 1101100 শিফট ছেড়ে চলে যান এবং তারপরে ডান শিফট করে থাকেন, আপনি একই ফলাফলটি আর পাবেন না।

N দ্বারা বাম দিকে স্থানান্তর করা 2 N দ্বারা গুণনের সমান ।

এন দ্বারা ডান স্থানান্তর হ'ল (আপনি যদি এর পরিপূরক ব্যবহার করছেন ) 2 এন দ্বারা বিভাজক এবং শূন্যকে গোল করার সমতুল্য ।

বিটশিফিংটি অতি দ্রুত গুন এবং বিভাগের জন্য ব্যবহার করা যেতে পারে, আপনি যদি ২. পাওয়ার নিয়ে কাজ করছেন তবে প্রায় সমস্ত নিম্ন স্তরের গ্রাফিক্সের রুটিনগুলি বিট শিফটিং ব্যবহার করে।

উদাহরণস্বরূপ, পুরানো দিনগুলিতে ফিরে আসার জন্য, আমরা গেমসের জন্য মোড 13 ঘন্টা (320x200 256 রঙ) ব্যবহার করি। মোডে 13 ঘন্টা, ভিডিও মেমরিটি পিক্সেল অনুসারে ক্রমানুসারে আউট করা হয়েছিল। এর অর্থ পিক্সেলের জন্য অবস্থান গণনা করা, আপনি নিম্নলিখিত গণিতটি ব্যবহার করবেন:

memoryOffset = (row * 320) + column

এখন, সেই দিন এবং যুগে ফিরে গতি সংকটপূর্ণ ছিল, তাই আমরা এই অপারেশনটি করতে বিটশিফ্ট ব্যবহার করব।

যাইহোক, 320 দুটি পাওয়ার নয়, সুতরাং এটিকে ঘুরে দেখার জন্য আমাদের খুঁজে বের করতে হবে যে দু'জনের শক্তি যা একসাথে যুক্ত করেছে 320:

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

এখন আমরা এটিকে বাম শিফটে রূপান্তর করতে পারি:

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

এর চূড়ান্ত ফলাফলের জন্য:

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

মোট: প্রাচীন সিপিইউতে যা যা ঘটেছিল তার 28 টি চক্রের সময় ছিল।

Vrs

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]

একই প্রাচীন সিপিইউতে 12 টি চক্র।

হ্যাঁ, আমরা 16 সিপিইউ চক্র বন্ধ করার জন্য এই কঠোর পরিশ্রম করব।

32 বা 64-বিট মোডে, উভয় সংস্করণ অনেক সংক্ষিপ্ত এবং দ্রুত পাওয়া যায়। ইন্টেল স্কাইলেকের মতো আধুনিক আউট-অফ-অর্ডার এক্সিকিউশন সিপিইউগুলিতে (দেখুন http://agner.org/optimize/ ) খুব দ্রুত হার্ডওয়্যার মাল্টিপল (লো ল্যাটেন্সি এবং হাই থ্রুপুট) রয়েছে, তাই লাভটি অনেক ছোট। এএমডি বুলডোজার-পরিবারটি কিছুটা ধীরে ধীরে, বিশেষত -৪-বিট গুণনের জন্য। ইন্টেল সিপিইউ, এবং এএমডি রাইজেনে, দুটি শিফট হ'ল কিছুটা কম লেটেন্সি তবে মাল্টিপ্লাইয়ের চেয়ে আরও বেশি নির্দেশনা (যা কম থ্রুপুটের দিকে নিয়ে যেতে পারে):

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; কীভাবে সমস্ত শিফট + লি ব্যবহার করে তা দেখুন

এখানে খেয়াল করা সবচেয়ে মজার বিষয় হল এক্স 86 একটি স্থানান্তর-এবং-অ্যাড নির্দেশ (হয়েছে LEA) ছোট বাম বদল আনতে এবং একটি কর্মক্ষমতাকে সঙ্গে, একই সময়ে যোগ করতে পারেন addনির্দেশ। এআরএম আরও বেশি শক্তিশালী: যে কোনও নির্দেশের একটি অপরেন্ড বিনামূল্যে বা বামে ডান স্থানান্তরিত করা যায়। সুতরাং একটি সংকলন-সময়-ধ্রুবক দ্বারা স্কেলিং যা -2-পাওয়ার হিসাবে পরিচিত। এটি একটি গুণকের চেয়ে আরও কার্যকর হতে পারে।


ঠিক আছে, আধুনিক যুগে ফিরে ... এখন আরও কার্যকর কিছু হ'ল 16-বিট সংখ্যায় দুটি 8-বিট মান সংরক্ষণ করতে বিট শিফটিং ব্যবহার করা। উদাহরণস্বরূপ, সি # তে:

// Byte1: 11110000
// Byte2: 00001111

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

// value = 000011111110000;

সি ++ এ, সংকলকগণ আপনার জন্য এটি করা উচিত যদি আপনি structদুটি 8-বিট সদস্যের সাথে একটি ব্যবহার করেন তবে বাস্তবে তারা সর্বদা তা না করে।


7
এটি প্রসারিত করে, ইন্টেল প্রসেসরগুলিতে (এবং আরও অনেকগুলি) এটি করা দ্রুত হয়: ইন সি, ডি; গ = D << 2; এর চেয়ে বেশি: সি = 4 * ডি; কখনও কখনও এমনকি "সি = ডি << 2 + ডি << 1" "সি = 6 * ডি" এর চেয়েও দ্রুত হয় !! আমি ডস যুগে গ্রাফিক কাজকর্মের জন্য ব্যাপকভাবে এই কৌশলগুলি ব্যবহার করা হয়, আমার মনে হয় না তারা যাতে দরকারী আর ... করছি
জো Pineda

4
@ জেমস: একেবারেই নয়, আজকাল এটি বরং ভিডিও-কার্ডের ফার্মওয়্যারের সিপিইউর পরিবর্তে জিপিইউ দ্বারা সম্পাদন করার মতো কোড অন্তর্ভুক্ত করে। সুতরাং তাত্ত্বিকভাবে আপনাকে গ্রাফিক ফাংশনগুলির জন্য এই জাতীয় কোড (বা কারম্যাকের ব্ল্যাক-ম্যাজিক ইনভার্স রুট ফাংশনের মতো) প্রয়োগ করতে হবে না :-)
জো পাইনেদা

2
সংকলক লেখকগণ অবশ্যই তাদের ব্যবহার করছেন @ লিখলে c=4*dশিফট পাবেন। আপনি যদি এটি লিখেন তবে k = (n<0)শিফট দিয়েও k = (n>>31)&1করা যেতে পারে: একটি শাখা এড়াতে। নীচের লাইন, সংকলকদের চতুরতার এই উন্নতির অর্থ সি কোডে এই কৌশলগুলি ব্যবহার করা এখন অপ্রয়োজনীয় এবং তারা পাঠযোগ্যতা এবং বহনযোগ্যতার সাথে আপস করে। আপনি যেমন এসএসই ভেক্টর কোড লিখছেন তবে তাদের জেনে এখনও খুব ভাল; অথবা যে কোনও পরিস্থিতি যেখানে আপনার এটি প্রয়োজন দ্রুত এবং একটি কৌশল আছে যা সংকলক ব্যবহার করছে না (যেমন জিপিইউ কোড)।
গ্রেগগো

2
আর একটি ভাল উদাহরণ: খুব সাধারণ জিনিসটি if(x >= 1 && x <= 9)যা if( (unsigned)(x-1) <=(unsigned)(9-1)) দুটি শর্তসাপেক্ষ পরীক্ষা এক হিসাবে পরিবর্তন করা একটি বড় গতির সুবিধা হতে পারে; বিশেষত যখন এটি শাখার পরিবর্তে পূর্বাভাস কার্যকর করতে দেয়। আমি এটি বছর কয়েক ধরে ব্যবহার করেছি (যেখানে ন্যায্য রয়েছে) যতক্ষণ না আমি 10 বছর আগে এই বিষয়টি লক্ষ্য করেছিলাম যে কম্পাইলাররা অপ্টিমাইজারটিতে এই রূপান্তরটি শুরু করেছিল, তখন আমি থামলাম। এখনও জেনে রাখা ভাল, যেহেতু অনুরূপ পরিস্থিতি রয়েছে যেখানে সংকলকটি আপনার জন্য রূপান্তর করতে পারে না। অথবা আপনি যদি একটি সংকলক নিয়ে কাজ করছেন।
গ্রেগগো

3
আপনার "বাইট" কেবল 7 বিট হওয়ার কোনও কারণ আছে?
ম্যাসন ওয়াটমোগ

103

বিট শিফট সহ বিটওয়াস অপারেশনগুলি নিম্ন-স্তরের হার্ডওয়্যার বা এম্বেডড প্রোগ্রামিংয়ের মৌলিক। আপনি যদি কোনও ডিভাইস বা এমনকি কিছু বাইনারি ফাইল ফর্ম্যাটগুলির জন্য কোনও বিশদ বিবরণ পড়ে থাকেন তবে আপনি বাইটস, শব্দ এবং ডিফল্টগুলি নন-বাইট বিন্যস্ত বিটফিল্ডে বিভক্ত দেখতে পাবেন, এতে আগ্রহের বিভিন্ন মান রয়েছে। পড়া / লেখার জন্য এই বিট-ফিল্ডগুলি অ্যাক্সেস করা সবচেয়ে সাধারণ ব্যবহার।

গ্রাফিক্স প্রোগ্রামিংয়ের একটি সাধারণ বাস্তব উদাহরণ হ'ল একটি 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-বিট নম্বর কারণ এটির এমএসবি 11 তম বিটে রয়েছে। সবুজটি কেবলমাত্র 6-বিট দীর্ঘ, তাই আমাদের ডান শিফট (11 - 6 = 5) ব্যবহার করে এটি স্কেল করা দরকার, সুতরাং অফসেট হিসাবে 5 ব্যবহার করুন ( #define GREEN_OFFSET 5)।

2 এর শক্তির দ্বারা দ্রুত গুণ এবং বিভাজনের জন্য বিট শিফট ব্যবহার করাও সাধারণ common

 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ইত্যাদি


আপনার আসলটি কাস্ট করা কি সহজ নয়, 32 বিট ক্লিওউইন্টকে, ক্লিওউচার 4 এর মতো কিছু বলে এবং আপনি বাইটটি * * এস 2 হিসাবে সরাসরি অ্যাক্সেস করতে চান?
ডেভিড এইচ প্যারি

27

একটি গোচা হ'ল নিম্নলিখিতটি বাস্তবায়ন নির্ভর (এএনএসআই মান অনুযায়ী):

char x = -1;
x >> 1;

এক্স এখন 127 (01111111) বা এখনও -1 (11111111) হতে পারে।

অনুশীলনে, এটি সাধারণত পরেরটি।


4
আমি যদি এটি সঠিকভাবে স্মরণ করি তবে এএনএসআই সি স্ট্যান্ডার্ড স্পষ্টভাবে বলেছে এটি বাস্তবায়ন-নির্ভর, সুতরাং আপনি যদি আপনার কোডটিতে স্বাক্ষরিত পূর্ণসংখ্যাগুলি ডান-শিফট করতে চান তবে এটি কীভাবে কার্যকর হয় তা দেখতে আপনার সংকলকটির ডকুমেন্টেশন পরীক্ষা করা উচিত।
জো পাইনেদা

হ্যাঁ, আমি নিজেই এএনএসআই স্ট্যান্ডার্ডটির উপরে জোর দিতে চেয়েছিলাম, এটি এমন কোনও ঘটনা নয় যেখানে বিক্রেতারা কেবল মান অনুসরণ করেন না বা স্ট্যান্ডার্ডটি এই বিবরণী সংক্রান্ত কেস সম্পর্কে কিছুই বলে না।
জো পাইনেদা

22

আমি কেবল টিপস এবং কৌশল লিখছি। এটি পরীক্ষা এবং পরীক্ষায় কার্যকর হতে পারে।

  1. n = n*2: n = n<<1
  2. n = n/2: n = n>>1
  3. এন 2 এর পাওয়ার (2,4,8,8, ...) কিনা তা পরীক্ষা করা হচ্ছে: চেক করুন !(n & (n-1))
  4. এর x বিট পাওয়া n:n |= (1 << x)
  5. X সমান বা বিজোড় কিনা তা পরীক্ষা করা হচ্ছে: x&1 == 0(এমনকি)
  6. X এর n তম বিট টগল করুন :x ^ (1<<n)

আরও কিছু অবশ্যই আছে যা আপনি এতক্ষণে জানেন?
রাইকার

@ রাইকার আমি আরও কয়েকটি যুক্ত করেছি। আমি এটি আপডেট করার চেষ্টা করব :)
রবি প্রকাশ

এক্স এবং এন 0 সূচী হয়?
রেগেগুইটার

বিজ্ঞাপন 5 .: এটি একটি নেতিবাচক সংখ্যা হলে কী হবে?
পিটার মর্টেনসেন

সুতরাং, আমরা বাইনারি 2 টি দশমিক 10 এর মতো সমাপ্তি করতে পারি? এবং বিট শিফটিং দশমিকের মধ্যে অন্য সংখ্যার পিছনে আরও একটি সংখ্যা যোগ বা বিয়োগের মতো?
উইলি স্যাট্রিও নগ্রোহো

8

নোট করুন যে জাভা বাস্তবায়নে, স্থানান্তরিত বিটের সংখ্যা উত্সের আকার অনুসারে Mod'd হয়।

উদাহরণ স্বরূপ:

(long) 4 >> 65

2 সমান। আপনি আশা করতে পারেন বিটগুলি ডান 65 বারে স্থানান্তরিত করলে সমস্ত কিছু শূন্য হয়ে যায়, তবে এটি আসলে এর সমতুল্য:

(long) 4 >> (65 % 64)

এটি <<, >> এবং >>> এর ক্ষেত্রে সত্য। আমি অন্য ভাষায় চেষ্টা করে দেখিনি।


হু, মজার! সি তে, এটি প্রযুক্তিগতভাবে অপরিবর্তিত আচরণgcc 5.4.0একটি সতর্কতা দেয়, কিন্তু 25 >> 65 এর জন্য দেয় ; যেমন.
পিজ্জাপ্যান্টস 184

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))

-3

সচেতন থাকুন যে উইন্ডোজ প্ল্যাটফর্মে কেবলমাত্র পিএইচপি এর 32 বিট সংস্করণ উপলব্ধ।

তারপরে যদি আপনি উদাহরণস্বরূপ << বা >> 31 বিটের চেয়ে বেশি স্থান পরিবর্তন করেন তবে ফলাফল অনাকাঙ্ক্ষিত। সাধারণত শূন্যের পরিবর্তে মূল সংখ্যাটি ফিরে আসবে এবং এটি সত্যই জটিল ত্রুটি হতে পারে।

অবশ্যই যদি আপনি পিএইচপি (ইউনিক্স) এর bit৪ বিট সংস্করণ ব্যবহার করেন তবে আপনার 63৩ টিরও বেশি বিট স্থানান্তর এড়ানো উচিত। তবে উদাহরণস্বরূপ, মাইএসকিউএল 64৪-বিট বিগিন্ট ব্যবহার করে, সুতরাং কোনও সামঞ্জস্যের সমস্যা হওয়া উচিত নয়।

আপডেট: পিএইচপি Windows উইন্ডোজ থেকে, পিএইচপি বিল্ডগুলি শেষ পর্যন্ত পুরো bit৪ বিট পূর্ণসংখ্যার ব্যবহার করতে সক্ষম হয়: একটি পূর্ণসংখ্যার আকার প্ল্যাটফর্ম নির্ভর although PH৪-বিট প্ল্যাটফর্মগুলির পিএইচপি 7 এর আগে উইন্ডোজ বাদে সাধারণত 9E18 এর সর্বাধিক মান থাকে, যেখানে এটি সর্বদা 32 বিট ছিল।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.