c++ - অখন - স্বাভাবিক সংখ্যা কি কি




একটি পূর্ণসংখ্যার ব্যাপ্তি দিয়ে আমি কী অপটিমাইজারটি ইঙ্গিত করতে পারি? (3)

আমি একটি মান সঞ্চয় করতে একটি int টাইপ ব্যবহার করছি। প্রোগ্রামটির শব্দার্থবিজ্ঞানের দ্বারা, মানটি সর্বদা খুব অল্প পরিসরে (0 - 36) পরিবর্তিত হয় এবং কেবলমাত্র CPU দক্ষতার কারণে int (কোন char ) ব্যবহৃত হয়।

দেখে মনে হচ্ছে অনেকগুলি সংখ্যার গাণিতিক অপ্টিমাইজেশানগুলি এত ছোট সংখ্যার পূর্ণসংখ্যার উপর সম্পাদন করা যেতে পারে। এই পূর্ণসংখ্যার উপর অনেকগুলি ফাংশন কলগুলি "জাদুকরী" ক্রিয়াকলাপের একটি ছোট সেটে অনুকূলিত হতে পারে এবং কিছু ফাংশন এমনকি টেবিলের চেহারাতে অনুকূলিত হতে পারে।

সুতরাং, এই int সর্বদা সেই ছোট পরিসরে থাকে এবং কম্পাইলারের পক্ষে those অনুকূলিতিগুলি করা কি সম্ভব?


আমি কেবল এই কথাটি বলতে চাইছি যে আপনি যদি আরও বেশি স্ট্যান্ডার্ড সি ++ এর সমাধান চান তবে আপনি নিজের [[noreturn]] লেখার জন্য [[noreturn]] বৈশিষ্ট্যটি ব্যবহার করতে পারেন।

সুতরাং আমি প্রত্যাখ্যান করার জন্য দুর্দান্ত উদাহরণটিকে অস্বীকার করব-

namespace detail {
    [[noreturn]] void unreachable(){}
}

#define assume(cond) do { if (!(cond)) detail::unreachable(); } while (0)

int func(int x){
    assume(x >=0 && x <= 10);

    if (x > 11){
        return 2;
    }
    else{
        return 17;
    }
}

যা আপনি দেখতে পাচ্ছেন , প্রায় অভিন্ন কোডের ফলাফল:

detail::unreachable():
        rep ret
func(int):
        movl    $17, %eax
        ret

নেতিবাচক [[noreturn]] অবশ্যই, যে আপনি একটি সতর্কতা পেয়েছেন যে একটি [[noreturn]] ফাংশন আসলেই ফিরে আসবে।


এটির জন্য স্ট্যান্ডার্ড সমর্থন রয়েছে। আপনার যা করা উচিত তা হল stdint.h ( cstdint ) অন্তর্ভুক্ত করা এবং তারপরে uint_fast8_t ব্যবহার করা।

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


হ্যা এটা সম্ভব. উদাহরণস্বরূপ, __builtin_unreachable জন্য আপনি __builtin_unreachable অসম্ভব পরিস্থিতি সম্পর্কে __builtin_unreachable বলতে, ব্যবহার করতে পারেন:

if (value < 0 || value > 36) __builtin_unreachable();

আমরা উপরের শর্তটি ম্যাক্রোতে গুটিয়ে রাখতে পারি:

#define assume(cond) do { if (!(cond)) __builtin_unreachable(); } while (0)

এবং এটি এর মতো ব্যবহার করুন:

assume(x >= 0 && x <= 10);

আপনি দেখতে পাচ্ছেন , gcc এই তথ্যের উপর ভিত্তি করে অপ্টিমাইজেশন সম্পাদন করে:

#define assume(cond) do { if (!(cond)) __builtin_unreachable(); } while (0)

int func(int x){
    assume(x >=0 && x <= 10);

    if (x > 11){
        return 2;
    }
    else{
        return 17;
    }
}

উত্পাদন:

func(int):
    mov     eax, 17
    ret

তবে একটি খারাপ দিক, আপনার কোডটি যদি কখনও এই ধরনের অনুমানগুলি ভঙ্গ করে তবে আপনি অপরিবর্তিত আচরণ পাবেন

এটি যখন ঘটে তখন আপনাকে অবহিত করে না, এমনকি ডিবাগ নির্মাণেও। আরও সহজে অনুমানের সাথে ডিবাগ / পরীক্ষা / বাগগুলি ধরতে, আপনি এর মতো একটি হাইব্রিড ধরে নেওয়া / জোড় করা ম্যাক্রো (@ ডেভিড জেড এর ক্রেডিট) ব্যবহার করতে পারেন:

#if defined(NDEBUG)
#define assume(cond) do { if (!(cond)) __builtin_unreachable(); } while (0)
#else
#include <cassert>
#define assume(cond) assert(cond)
#endif

ডিবাগ বিল্ডগুলিতে ( NDEBUG সংজ্ঞায়িত না করে ) এটি সাধারণ চাপ, প্রিন্টিং ত্রুটি বার্তা এবং NDEBUG প্রোগ্রামের মতো কাজ করে এবং রিলিজে এটি অনুমানের ব্যবহার করে, অনুকূলিত কোড তৈরি করে।

তবে নোট করুন, এটি নিয়মিত assert বিকল্প নয় - cond রিলিজ assume(VeryExpensiveComputation()) যায়, সুতরাং আপনার assume(VeryExpensiveComputation()) মতো খুব ভাল কিছু করা উচিত নয় assume(VeryExpensiveComputation())






compiler-optimization