স্টাড :: বিটসেটের উপরে সি-স্টাইল বিট ম্যানিপুলেশনের কোনও সুবিধা আছে কি?


17

আমি সি ++ 11/14-এ প্রায় একচেটিয়াভাবে কাজ করি এবং যখন আমি এই জাতীয় কোড দেখি তখন সাধারণত ক্রিঞ্জ হয়:

std::int64_t mArray;
mArray |= someMask << 1;

এইটা শুধুমাত্র একটা উদাহরণ; আমি সাধারণভাবে বিট-বুদ্ধিমান হেরফের সম্পর্কে কথা বলছি। সি ++ তে আসলে কী কোনও বক্তব্য আছে? উপরেরটি হ'ল মাইন্ড-ওয়ার্পিং এবং ত্রুটি-প্রবণ, যখন একটি ব্যবহার করে std::bitsetআপনি এটি করতে পারবেন:

  1. std::bitsetএকটি টেমপ্লেট প্যারামিটার সামঞ্জস্য করে এবং বাস্তবায়নটিকে বাকী যত্ন নেওয়ার সুযোগ দিয়ে আরও সহজে আকারের আকারটি পরিবর্তন করুন এবং
  2. কী চলছে (এবং সম্ভবত ভুল করা হচ্ছে) তা নির্ধারণ করার জন্য কম সময় ব্যয় করুন এবং অন্যান্য ডেটা পাত্রে std::bitsetঅনুরূপ পদ্ধতিতে লিখুন std::array

আমার প্রশ্ন; পশ্চাৎ-সামঞ্জস্যতা বাদে আদিম ধরণের বেশি ব্যবহার না করার কোনও কারণ আছে std::bitsetকি?


একটি এর আকার std::bitsetসংকলন সময়ে স্থির করা হয়। আমি ভাবতে পারি এটিই একমাত্র পঙ্গু দোষ।
রোবং

1
@ রুং আমি std::bitsetবনাম সি-স্টাইল বিট ম্যানিপুলেশন (উদাহরণস্বরূপ int) সম্পর্কে কথা বলছি , যা সংকলন-সময় স্থির করা হয়েছে।
কোয়ান্ট

লিগ্যাসি কোডের একটি কারণ হতে পারে: কোডটি তখন লেখা ছিল যখন std::bitsetউপলব্ধ ছিল না (বা লেখকের কাছে জানা ছিল) এবং কোডটি ব্যবহার করার জন্য পুনরায় লেখার কোনও কারণ নেই std::bitset
বার্ট ভ্যান ইনজেন শেনৌ

আমি ব্যক্তিগতভাবে মনে করি যে "বাইনারি ভেরিয়েবলগুলির সেট / মানচিত্র / অ্যারেতে অপারেশন" কীভাবে তৈরি করা যায় সে বিষয়টি সবার কাছে সহজেই বোঝা এখনও মূলত অমীমাংসিত, কারণ প্রচলিত অনেক অপারেশন রয়েছে যা সাধারণ অপারেশনগুলিতে হ্রাস করা যায় না। এই জাতীয় সেটগুলির প্রতিনিধিত্ব করার অনেকগুলি উপায় রয়েছে যার bitsetমধ্যে একটি, তবে একটি ছোট ভেক্টর বা intগুলি (বিট সূচক) এর সেটও বৈধ হতে পারে। সি / সি ++ এর দর্শন প্রোগ্রামার থেকে এই পছন্দগুলি জটিলতাগুলি আড়াল করে না।
রবিং

উত্তর:


12

যৌক্তিক (অ-প্রযুক্তিগত) দৃষ্টিকোণ থেকে, কোনও সুবিধা নেই।

যে কোনও সরল সি / সি ++ কোড উপযুক্ত "লাইব্রেরি কনস্ট্রাক্ট" এর মধ্যে মোড়ানো যায়। এই ধরণের মোড়কের পরে, "এটি এর চেয়ে আরও সুবিধাজনক কিনা" বিষয়টি একটি মূল প্রশ্নে পরিণত হয়।

স্পিড পয়েন্ট অফ দ্য ভিউ থেকে, সি / সি ++ গ্রন্থাগারটি এমন কোড তৈরির অনুমতি দেয় যা এটি প্লেইন কোডের মতো কার্যকর is এটি তবে সাপেক্ষে:

  • ফাংশন ইনলাইনিং
  • সংকলন-সময় চেকিং এবং অপ্রয়োজনীয় রানটাইম চেকিং নির্মূলকরণ
  • ডেড কোড নির্মূলকরণ
  • অন্যান্য অনেক কোড অপ্টিমাইজেশন ...

এই ধরণের অ-প্রযুক্তিগত যুক্তি ব্যবহার করে যে কোনও "অনুপস্থিত ফাংশন" যে কেউ যুক্ত করতে পারে এবং তাই অসুবিধা হিসাবে গণ্য হয় না।

তবে অতিরিক্ত কোড সহ অন্তর্নির্মিত প্রয়োজনীয়তা এবং সীমাবদ্ধতাগুলি কাটিয়ে উঠতে পারে না। নীচে, আমি যুক্তি দিচ্ছি যে আকারটি std::bitsetএকটি সংকলন-সময় ধ্রুবক, এবং অতএব অসুবিধে হিসাবে গণ্য না হলেও এটি এখনও এমন কিছু যা ব্যবহারকারীর পছন্দকে প্রভাবিত করে।


একটি নান্দনিক দৃষ্টিকোণ থেকে (পঠনযোগ্যতা, রক্ষণাবেক্ষণের স্বাচ্ছন্দ্য ইত্যাদি) থেকে ভিন্নতা রয়েছে is

তবে, এটি স্পষ্ট নয় যে std::bitsetকোডটি সাথে সাথে প্লেইন সি কোডের উপরে জয়লাভ করে। কোডের বড় টুকরো (এবং খেলনা-নমুনার কিছু নয়) দেখতে হবে যে std::bitsetউত্স কোডের ব্যবহারের ফলে মানুষের মান উন্নত হয়েছে কিনা ।


বিট ম্যানিপুলেশনের গতি কোডিং শৈলীর উপর নির্ভর করে। কোডিং স্টাইলটি সি / সি ++ বিট ম্যানিপুলেশন উভয়কেই প্রভাবিত করে এবং নীচে std::bitsetবর্ণিত হিসাবে বর্ণিত হিসাবে একইভাবে প্রযোজ্য ।


যদি কেউ এমন কোড লিখে থাকে যা operator []একবারে একটি বিট পড়তে এবং লিখতে ব্যবহার করে, যদি একাধিক বিট ম্যানিপুলেট করতে হয় তবে একাধিকবার এটি করতে হবে। সি-স্টাইল কোড সম্পর্কে একই কথা বলা যেতে পারে।

যাইহোক, bitsetযেমন হিসাবে অন্যান্য অপারেটর, হয়েছে operator &=, operator <<=ইত্যাদি, যা bitset পূর্ণ প্রস্থ উপর কাজ করে। কারণ অন্তর্নিহিত যন্ত্রপাতি প্রায়শই 32-বিট, 64-বিট এবং কখনও কখনও 128-বিট (সিমডি সহ) একসাথে (একই সংখ্যক সিপিইউ চক্রের), এমন কোড ব্যবহার করে যা এমন মাল্টি-বিট ক্রিয়াকলাপগুলির সুবিধা নিতে ডিজাইন করা হয়েছে "লুপী" বিট-ম্যানিপুলেশন কোডের চেয়ে দ্রুত হতে পারে।

সাধারণ ধারণাটিকে স্বর (একটি রেজিস্টারের মধ্যে সিমডি ) বলা হয় এবং এটি বিট ম্যানিপুলেশনের অধীনে একটি সাবটোপিক।


কিছু সি ++ বিক্রেতারা bitsetসিমডের সাথে 64-বিট এবং 128-বিটের মধ্যে প্রয়োগ করতে পারে । কিছু বিক্রেতারা নাও করতে পারেন (তবে শেষ পর্যন্ত তা করতে পারে)। যদি সি ++ বিক্রেতার লাইব্রেরিটি কী করছে তা যদি জানতে হয় তবে একমাত্র উপায় হ'ল বিচ্ছিন্নতা দেখা।


std::bitsetসীমাবদ্ধতা আছে কিনা তা হিসাবে , আমি দুটি উদাহরণ দিতে পারি।

  1. std::bitsetসংকলনের সময় আকারটি অবশ্যই জানা উচিত। গতিশীল চয়ন করা আকারের সাথে বিটের একটি অ্যারে তৈরি করতে, একটি ব্যবহার করতে হবে std::vector<bool>
  2. বর্তমানের সি ++ স্পেসিফিকেশন বড় বড় বি std::bitsetবিট থেকে N বিটগুলির একটানা টুকরো বের করার কোনও উপায় সরবরাহ করে না bitset

প্রথমটি মৌলিক, যার অর্থ গতিশীল আকারের বিটসেটগুলির প্রয়োজন তাদের অবশ্যই অন্যান্য বিকল্প নির্বাচন করতে হবে choose

দ্বিতীয়টি কাটিয়ে উঠতে পারে, কারণ স্ট্যান্ডার্ডটি এক্সটেনসিবল না হলেও কোনওটি টাস্কটি সম্পাদনের জন্য কিছু প্রকারের অ্যাডাপ্টার লিখতে পারে bitset


কিছু নির্দিষ্ট ধরণের উন্নত এসওআর অপারেশন রয়েছে যা বাইরের বাইরে সরবরাহ করা হয় না std::bitsetবিট পারমিটেশন সম্পর্কে এই ওয়েবসাইটটিতে এই অপারেশনগুলি সম্পর্কে কেউ পড়তে পারেন । যথারীতি, কেউ এগুলি নিজের উপর প্রয়োগ করতে পারে এবং উপরে কাজ করে std::bitset


পারফরম্যান্স নিয়ে আলোচনা সম্পর্কিত Regarding

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

যেহেতু সাধারণভাবে আমরা বলতে পারি না যে কেউ (ইন্টারনেটে) সঠিকভাবে মাইক্রোবেইনমার্কগুলি করছে কিনা, তাই নির্ভরযোগ্য উপসংহার পাওয়ার একমাত্র উপায় হ'ল আমাদের নিজস্ব মাইক্রোব্যাঙ্কমার্কগুলি করা, এবং বিশদটি নথিভুক্ত করা, এবং জনসাধারণের পর্যালোচনা এবং সমালোচনাতে জমা দেওয়া। অন্যরা এর আগে যে মাইক্রোব্যাঙ্কমার্কগুলি করেছে তা পুনরায় করাতে ক্ষতি হয় না।


ইস্যু # 2 এর অর্থ হ'ল বিটসেট কোনও সমান্তরাল সেটআপে ব্যবহার করা যাবে না যেখানে প্রতিটি থ্রেড বিটসেটের উপসেটে কাজ করা উচিত।
ব্যবহারকারী 239558

@ ব্যবহারকারী 239558 আমি সন্দেহ করি যে কেউ এর সাথে সমান্তরাল করতে চাইবে std::bitset। কোনও মেমরি ধারাবাহিকতা গ্যারান্টি নেই (ইন std::bitset), যার অর্থ এটি কোরগুলির মধ্যে ভাগ করে নেওয়া উচিত নয়। যে সমস্ত ব্যক্তিকে কোর জুড়ে ভাগ করে নেওয়া দরকার তাদের নিজস্ব বাস্তবায়ন তৈরি করার প্রবণতা রয়েছে। যখন বিভিন্ন কোরের মধ্যে ডেটা ভাগ করা হয় তখন তাদের ক্যাশে লাইনের সীমানায় প্রান্তিক করার প্রথাগত। এটি না করা পারফরম্যান্স হ্রাস করে এবং আরও অ-পারমাণবিক সমস্যাগুলি প্রকাশ করে। এর সমান্তরাল বাস্তবায়ন কীভাবে তৈরি করা যায় সে সম্পর্কে একটি ওভারভিউ দেওয়ার মতো পর্যাপ্ত জ্ঞান আমার নেই std::bitset
রবিং

ডেটা সমান্তরাল প্রোগ্রামিংয়ে সাধারণত কোনও মেমরির ধারাবাহিকতা প্রয়োজন হয় না। আপনি কেবল পর্যায়গুলির মধ্যে সিঙ্ক্রোনাইজ করেন। আমি একেবারে সমান্তরালভাবে একটি বিটসেট প্রক্রিয়া করতে চাই, আমি মনে করি যে একটি বৃহত bitsetইচ্ছা আছে।
ব্যবহারকারী 239558

@ ব্যবহারকারী 239558 যেগুলি অনুলিপি করে মনে হচ্ছে (প্রতিটি কোর দ্বারা প্রসেস করা বিটসেটের প্রাসঙ্গিক পরিসীমা প্রসেসিং শুরু হওয়ার আগে অনুলিপি করা উচিত)। আমি এর সাথে একমত, যদিও আমি মনে করি যে যে কেউ সমান্তরালত্বের কথা ভাবছেন তারা ইতিমধ্যে তাদের নিজস্ব বাস্তবায়ন কার্যকর করার বিষয়ে ভাববেন। সাধারণভাবে, বেসলাইন বাস্তবায়ন হিসাবে প্রচুর সি ++ স্ট্যান্ডার্ড লাইব্রেরি সুবিধা সরবরাহ করা হয়; আরও গুরুতর প্রয়োজনে যে কেউ তাদের নিজস্ব বাস্তবায়ন করতে চলেছে।
rwong

না কোন অনুলিপি আছে। এটি কেবল স্ট্যাটিক ডেটা কাঠামোর বিভিন্ন অংশে অ্যাক্সেস করে। কোন সিঙ্ক্রোনাইজেশন প্রয়োজন হয় না।
ব্যবহারকারী 239558

2

এটি অবশ্যই সব ক্ষেত্রে প্রযোজ্য নয়, তবে মাঝে মাঝে একটি অ্যালগরিদম সি-স্টাইলের বিট-টুইডলিংয়ের কার্যকারিতা অর্জনের জন্য উল্লেখযোগ্য পারফরম্যান্সের উপর নির্ভর করে। আমার মনে যে প্রথম উদাহরণটি আসে তা হ'ল বিটবোর্ড ব্যবহার, বোর্ড গেম পজিশনের চতুর পূর্ণসংখ্যার এনকোডিংগুলি, দাবা ইঞ্জিনগুলি এবং এর মতো গতি বাড়ানো । এখানে, পূর্ণ আকারের নির্দিষ্ট আকারের কোনও সমস্যা নেই, যেহেতু দাবাবোর্ডগুলি সর্বদা 8 * 8 হয় are

একটি সাধারণ উদাহরণের জন্য, নিম্নলিখিত ফাংশনটি বিবেচনা করুন ( বেন জ্যাকসনের এই উত্তর থেকে নেওয়া ) যা বিজয়ের জন্য একটি কানেক্ট ফোর অবস্থান পরীক্ষা করে:

// return whether newboard includes a win
bool haswon2(uint64_t newboard)
{
    uint64_t y = newboard & (newboard >> 6);
    uint64_t z = newboard & (newboard >> 7);
    uint64_t w = newboard & (newboard >> 8);
    uint64_t x = newboard & (newboard >> 1);
    return (y & (y >> 2 * 6)) | // check \ diagonal
           (z & (z >> 2 * 7)) | // check horizontal -
           (w & (w >> 2 * 8)) | // check / diagonal
           (x & (x >> 2));      // check vertical |
}

2
আপনি কি মনে করেন একটি std::bitsetকোনো ধীর হবে?
কোয়ান্ট

1
ঠিক আছে, উত্সটিতে এক ঝলক দেখে, libc ++ বিটসেটটি একটি একক আকারের_আর বা তাদের একটি অ্যারের উপর ভিত্তি করে তৈরি করা হয়, তাই সম্ভবত মূলত সমতুল্য / অভিন্ন কিছু তৈরি করে বিশেষত এমন একটি সিস্টেমে যেখানে আকারের (আকার_t) == 8 - সুতরাং না, এটি সম্ভবত কোনও ধীর হবে না।
রায়ান পাভলিক
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.