কিছুটা বুলিয়ান এর সাথে তুলনা করছি


12

বলুন যে আমার কাছে পতাকাগুলির একটি সেট রয়েছে, একটি uint16_t এ এনকোড করা আছে flags। উদাহরণস্বরূপ AMAZING_FLAG = 0x02,। এখন, আমি একটি ফাংশন আছে। এই ফাংশনটিতে আমি পতাকাটি পরিবর্তন করতে চাই কিনা তা যাচাই করা দরকার, কারণ যদি আমি এটি করতে চাই তবে আমার ফ্ল্যাশ লিখতে হবে। এবং যে ব্যয়বহুল। অতএব, আমি একটি চেক চাই যা flags & AMAZING_FLAGসমান কিনা তা আমাকে বলে doSet। এটি প্রথম ধারণা:

setAmazingFlag(bool doSet)
{
    if ((flags & AMAZING_FLAG) != (doSet ? AMAZING_FLAG : 0)) {
        // Really expensive thing
        // Update flags
    }
}

বিবৃতিটি স্বজ্ঞাত নয়। আমার মনে হয় এর চেয়ে ভাল উপায় হওয়া উচিত, এরকম কিছু:

if ((flags & AMAZING_FLAG) != doSet){

}

তবে এটি আসলে কাজ করে না, trueসমান বলে মনে হয় 0x01

সুতরাং, একটি বুলিয়ান সঙ্গে কিছু তুলনা করার জন্য একটি ঝরঝরে উপায় আছে?


2
আপনার যুক্তি কী হতে হবে তা সম্পূর্ণরূপে পরিষ্কার নয়। তাদের মত হচ্ছে, (flags & AMAZING_FLAG) && doSet?
কায়লুম

প্রশ্নটি পরিষ্কার নয়। আমরা 'পতাকা' 0x01 কিনা তা যাচাই করতে চাই। আপনি কি চান? যদি হ্যাঁ, তবে আমরা বিটওয়াইড অপারেটর 'এবং' ব্যবহার করতে পারি।
বিকাশ বিজয়ন

যদি আপনি এটিকে আরও পঠনযোগ্য কল সেটআমাজিংফ্ল্যাগ করতে চান কেবল তখনই যখন doSet সত্য হয়, তবে ফাংশনটির নামটি আরও ভাল করে পরীক্ষা করে দেখানো হয় অন্যথায় আপনার একটি ফাংশন রয়েছে যা নামটি যা বলে যা করতে পারে বা নাও করতে পারে, খারাপ কোড পঠনের জন্য করে তোলে
AndersK

আপনি যা করার চেষ্টা করছেন তা যদি এটিকে আরও পঠনযোগ্য করে তোলা হয় তবে কেবল একটি ফাংশন তৈরি করুন gs ফ্ল্যাগসনটকাল ``
জেরোইন 3

উত্তর:


18

যে কোনও অ-শূন্য নম্বরকে 1 (সত্য) এ রূপান্তর করতে, একটি পুরানো কৌশল রয়েছে: !দু'বার (না) অপারেটর প্রয়োগ করুন ।

if (!!(flags & AMAZING_FLAG) != doSet){

4
বা (bool)(flags & AMAZING_FLAG) != doSet- যা আমি আরও সরাসরি খুঁজে পাই। (যদিও এটি সূচিত করে যে মিঃ মাইক্রোসফ্ট এর সাথে এটির একটি সমস্যা রয়েছে)) এছাড়াও, ((flags & AMAZING_FLAG) != 0)সম্ভবত এটি ঠিক এটির সংকলন করে এবং একেবারে সুস্পষ্ট।
ক্রিস হল

"এছাড়াও, ((পতাকা এবং আমাজিং_এফএলএজি)! = 0) সম্ভবত এটি যা সংকলন করে এবং একেবারে সুস্পষ্ট। এটা হবে? ডুসেট যদি সত্য হয়?
চিরোন

@ ক্রিসহল 1 (2) এর ফলাফল 2 বা এটি এখনও 2, সি?
ব্যবহারকারী 253751

3
সি 11 স্ট্যান্ডার্ড, 6.3.1.2 বুলিয়ান টাইপ: "যখন কোনও স্কেলারের মান _ বুলে রূপান্তরিত হয়, তখন মান 0 এর সাথে তুলনা করলে ফলাফল 0 হয়; অন্যথায়, ফলাফল 1 হয়"। এবং .5. Cast.৪ কাস্ট অপারেটর: "প্রথম বন্ধনযুক্ত টাইপের নামের মাধ্যমে একটি এক্সপ্রেশনের পূর্বে অভিব্যক্তির মানটিকে নামকরণে রুপান্তর করে" "
ক্রিস হল

@ শেইরন, পরিষ্কার হতে হবে: ((bool)(flags & AMAZING_FLAG) != doSet)এর একই প্রভাব রয়েছে (((flags & AMAZING_FLAG) != 0) != doSet)এবং তারা উভয়ই সম্ভবত একই জিনিসটি সংকলন করবেন। প্রস্তাবিত (!!(flags & AMAZING_FLAG) != doSet)সমতুল্য, এবং আমি কল্পনাও করেছি একই জিনিসটিও সংকলন করব। এটি সম্পূর্ণরূপে স্বাদের বিষয় যা আপনার মনে হয় যা পরিষ্কার: (bool)অভিনেত্রীর আপনাকে কীভাবে কুল এবং কীভাবে _ দুর্দান্ত কাজ করতে রূপান্তর করা উচিত তা মনে রাখা দরকার; এর !!জন্য কিছু অন্যান্য মানসিক জিমন্যাস্টিকের প্রয়োজন হয় বা আপনার জন্য "কৌশল" জানতে হবে।
ক্রিস হল

2

আপনাকে বিট মাস্ককে একটি বুলিয়ান বিবৃতিতে রূপান্তর করতে হবে, যা সিতে মানগুলির সমতুল্য 0বা 1

  • (flags & AMAZING_FLAG) != 0। সর্বাধিক সাধারণ উপায়।

  • !!(flags & AMAZING_FLAG)। কিছুটা সাধারণ, ব্যবহার করা ঠিক আছে তবে কিছুটা ক্রিপ্টিকও।

  • (bool)(flags & AMAZING_FLAG)। C99 থেকে আধুনিক সি পথ এবং কেবল এর বাইরে।

উপরে বিকল্প কোন নিন, তারপর আপনার বুলিয়ান ব্যবহার করে এটি তুলনা !=বা ==


1

যৌক্তিক দৃষ্টিকোণ থেকে, flags & AMAZING_FLAGঅন্যান্য সমস্ত পতাকাকে মাস্কিংয়ের জন্য কেবল কিছুটা অপারেশন। ফলাফলটি একটি সংখ্যাসূচক মান।

বুলিয়ান মান পেতে, আপনি একটি তুলনা ব্যবহার করবেন

(flags & AMAZING_FLAG) == AMAZING_FLAG

এবং এখন এই যৌক্তিক মানটির সাথে তুলনা করতে পারি doSet

if (((flags & AMAZING_FLAG) == AMAZING_FLAG) != doSet)

সিতে সংক্ষিপ্তসারগুলি হতে পারে, কারণ বুলিয়ান মানগুলিতে সংখ্যার অন্তর্নিহিত রূপান্তর নিয়মের কারণে। সুতরাং আপনি লিখতে পারে

if (!(flags & AMAZING_FLAG) == doSet)

আরও নিবিড় লিখতে। তবে পাঠ্যযোগ্যতার দিক থেকে আগের সংস্করণটি আরও ভাল।


1

আপনি doSetমানের উপর ভিত্তি করে একটি মুখোশ তৈরি করতে পারেন :

#define AMAZING_FLAG_IDX 1
#define AMAZING_FLAG (1u << AMAZING_FLAG_IDX)
...

uint16_t set_mask = doSet << AMAZING_FLAG_IDX;

এখন আপনার চেকটি দেখতে এইরকম হতে পারে:

setAmazingFlag(bool doSet)
{
    const uint16_t set_mask = doSet << AMAZING_FLAG_IDX;

    if (flags & set_mask) {
        // Really expensive thing
        // Update flags
    }
}

কিছু স্থাপত্যগুলিতে !!কোনও শাখায় সংকলিত হতে পারে এবং এর মাধ্যমে আপনার দুটি শাখা থাকতে পারে:

  1. দ্বারা সাধারণীকরণ !!(expr)
  2. তুলনা করা doSet

আমার প্রস্তাবনার সুবিধাটি একটি গ্যারান্টিযুক্ত একক শাখা।

দ্রষ্টব্য: নিশ্চিত হয়ে নিন যে আপনি 30 টিরও বেশি বামে স্থানান্তরিত দ্বারা সংজ্ঞায়িত আচরণ প্রবর্তন করছেন না (ধরে নেওয়া হচ্ছে পূর্ণসংখ্যা 32 বিট) এটি সহজেই একটি দ্বারা অর্জন করা যেতে পারেstatic_assert(AMAZING_FLAG_IDX < sizeof(int)*CHAR_BIT-1, "Invalid AMAZING_FLAG_IDX");


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

1
@ লন্ডিন, নিশ্চিত, সে কারণেই আমি "কিছু কিছু স্থাপত্যে" লিখেছিলাম ...
অ্যালেক্স লোপ।

1
এটি বেশিরভাগই সংকলকের অপ্টিমাইজারের পক্ষে এবং এটি আইএসএ নিজেই নয়।
লন্ডিন

1
@ লন্ডিন আমি একমত নই কিছু আর্কিটেকচারের শর্তসাপেক্ষ বিট সেট / রিসেটের জন্য আইএসএ থাকে যেখানে কোনও ব্রাচের প্রয়োজন হয় না, অন্যরা তা করে না। Godbolt.org/z/4FDzvw
অ্যালেক্স লপ।

নোট: আপনি এই কাজ করতে পারেন, সংজ্ঞায়িত দয়া AMAZING_FLAGপরিপ্রেক্ষিতে AMAZING_FLAG_IDX(যেমন #define AMAZING_FLAG ((uint16_t)(1 << AMAZING_FLAG_IDX))), তাই আপনি একই তথ্য দুটি স্থান যেমন যে এক আপডেট করা পারেনি (থেকে বলুন, সংজ্ঞায়িত না 0x4করতে 0x8অন্যান্য সময়) ( IDXএর 2) অপরিবর্তিত ছেড়ে দেওয়া হয় ।
শ্যাডোর্যাঞ্জার

-1

এই পরীক্ষাটি করার একাধিক উপায় রয়েছে:

টেরিনারি অপারেটর ব্যয়বহুল লাফিয়ে উত্পন্ন করতে পারে:

if ((flags & AMAZING_FLAG) != (doSet ? AMAZING_FLAG : 0))

আপনি বুলিয়ান রূপান্তরও ব্যবহার করতে পারেন যা কার্যকর হতে পারে বা নাও পারে:

if (!!(flags & AMAZING_FLAG) != doSet)

বা এর সমতুল্য বিকল্প:

if (((flags & AMAZING_FLAG) != 0) != doSet)

গুণগুলি যদি সস্তা হয় তবে আপনি এর সাথে জাম্প এড়াতে পারবেন:

if ((flags & AMAZING_FLAG) != doSet * AMAZING_FLAG)

যদি flagsস্বাক্ষরবিহীন থাকে এবং সংকলকটি খুব স্মার্ট হয় তবে নীচের বিভাগটি একটি সাধারণ শিফটে সংকলন করতে পারে:

if ((flags & AMAZING_FLAG) / AMAZING_FLAG != doSet)

যদি আর্কিটেকচারটি দুটি পরিপূরক গাণিতিক ব্যবহার করে তবে এখানে অন্য বিকল্প রয়েছে:

if ((flags & AMAZING_FLAG) != (-doSet & AMAZING_FLAG))

পর্যায়ক্রমে, কেউ flagsবিটফিল্ড সহ একটি কাঠামো হিসাবে সংজ্ঞায়িত করতে পারে এবং আরও সহজভাবে একটি পঠনযোগ্য বাক্য গঠন ব্যবহার করতে পারে :

if (flags.amazing_flag != doSet)

হায়, এই পদ্ধতির উপর সাধারণত দৃষ্টিপাত করা হয় কারণ বিটফিল্ডগুলির স্পেসিফিকেশন বিট-স্তর বাস্তবায়নের উপর সঠিক নিয়ন্ত্রণের অনুমতি দেয় না।


যে কোনও কোডের প্রাথমিক লক্ষ্যটি পঠনযোগ্যতা হওয়া উচিত, যা আপনার বেশিরভাগ উদাহরণ নয়। একটি বড় সমস্যা দেখা দেয় যখন আপনি প্রকৃতপক্ষে আপনার উদাহরণগুলি একটি সংকলকটিতে লোড করেন: প্রাথমিক দুটি উদাহরণ প্রয়োগের সর্বোত্তম পারফরম্যান্স থাকে: ন্যূনতম পরিমাণে জাম্প এবং বোঝা (এআরএম 8.2, -ও) (সেগুলি সমতুল্য)। অন্যান্য সমস্ত বাস্তবায়ন আরও খারাপ সম্পাদন করে। সাধারণভাবে, কাউকে অভিনব স্টাফগুলি (মাইক্রো-অপ্টিমাইজেশন) করা এড়ানো উচিত, কারণ কী ঘটছে তা নির্ধারণের জন্য আপনি সংকলকটির পক্ষে আরও শক্ত করে তুলবেন, যা কর্মক্ষমতা হ্রাস করে। অতএব, -1।
চেরোন
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.