সিতে শিফট অপারেটরগুলি ব্যবহার করে গুণ এবং বিভাগগুলি কি দ্রুততর হয়?


287

উদাহরণস্বরূপ, বিট অপারেটরগুলি ব্যবহার করে গুণ ও বিভাগ অর্জন করা যায়

i*2 = i<<1
i*3 = (i<<1) + i;
i*10 = (i<<3) + (i<<1)

ইত্যাদি।

সরাসরি (i<<3)+(i<<1)ব্যবহারের চেয়ে 10 দিয়ে গুণিত করার জন্য এটি ব্যবহার করা আসলে কী দ্রুত i*10? এমন কোনও ধরণের ইনপুট রয়েছে যা এইভাবে গুণ বা ভাগ করা যায় না?


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

46
এটি এমন কিছুর মতো শোনায় যা সহজেই পরীক্ষা করা যায়।
janchopanza

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

19
এছাড়াও, সাবধান যে ডান স্থানান্তর কেবল স্বাক্ষরবিহীন পূর্ণসংখ্যার জন্য ভাল সংজ্ঞায়িত । আপনার যদি স্বাক্ষরিত পূর্ণসংখ্যা থাকে তবে 0 বা সর্বোচ্চ বিটটি বাম দিক থেকে প্যাড করা হয়েছে কিনা তা নির্ধারণ করা হয়নি। (এবং এক বছর পরে কোডটি পড়তে অন্য কারও (এমনকি নিজেকে) সময় লাগবে না!)
কেরেক এসবি

29
প্রকৃতপক্ষে, একটি ভাল অনুকূলকরণ সংকলক যখন দ্রুত হয় তখন শিফ্টগুলির সাথে গুণ এবং বিভাগ প্রয়োগ করে।
পিটার জি।

উত্তর:


486

সংক্ষিপ্ত উত্তর: সম্ভবত না।

দীর্ঘ উত্তর: আপনার সংকলকটিতে এটিতে একটি অপ্টিমাইজার রয়েছে যা আপনার টার্গেট প্রসেসরের আর্কিটেকচার সক্ষম হিসাবে যত তাড়াতাড়ি গুন করতে জানে। আপনার সর্বোত্তম বাজি হ'ল সংকলকটি আপনার উদ্দেশ্যটি স্পষ্টভাবে বলা (অর্থাত্ আমি << 1 এর চেয়ে i * 2) এবং দ্রুত সমাবেশ / মেশিন কোড সিকোয়েন্সটি কী তা তা নির্ধারণ করুন। এমনকি এটিও সম্ভব যে প্রসেসর নিজেই একাধিক নির্দেশকে শিফ্টের ক্রম হিসাবে প্রয়োগ করেছে এবং মাইক্রোকোডে যুক্ত করেছে।

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


31
হ্যাঁ, যেমনটি বলা হয়েছে যে প্রায় প্রতিটি প্রয়োগের সম্ভাব্য লাভগুলি সম্পূর্ণভাবে প্রবর্তিত অস্পষ্টতা ছাড়িয়ে যাবে। এই ধরণের অপ্টিমাইজেশন অকাল আগে নিয়ে চিন্তা করবেন না। যা অর্ধিকভাবে পরিষ্কার তা তৈরি করুন, বাধা চিহ্নিত করুন এবং সেখান থেকে অনুকূলিত করুন ...
ডেভ

4
রাজি পাঠযোগ্যতা এবং maintainability সম্ভবত আপনি নেট হবে আরও বেশি সময় কিছু আসলে নিখুঁত যে ব্যয় করার জন্য নিখুঁত প্রোফাইলার বলেছেন গরম কোড পাথ।
ডগ 65536

5
এই মন্তব্যগুলি এটিকে শোনাচ্ছে যে আপনি কম্পাইলারের কাজটি কীভাবে করবেন তা বলার থেকে আপনি সম্ভাব্য পারফরম্যান্স ছেড়ে চলে যাচ্ছেন। এই ক্ষেত্রে হয় না । আপনি শিফট সংস্করণের চেয়ে x86 থেকে আসলে আরও ভাল কোড পাবেন । যে কেউ সংকলক আউটপুটটি অনেকটা দেখছেন (আমার অনেকগুলি asm / অনুকূলিতকরণ উত্তর দেখুন), আমি অবাক হই না। অনেক সময় আছে যখন এটি কাজ করার এক উপায়ের মধ্যে সংকলকটি হাত ধরে রাখতে সহায়তা করতে পারে তবে এটি তাদের মধ্যে একটি নয়। জিসিসি পূর্ণসংখ্যার গণিতে ভাল, কারণ এটি গুরুত্বপূর্ণ। gcc -O3return i*10
পিটার কর্ডেস

সবেমাত্র একটি আরডুইনো স্কেচ ডাউনলোড করেছেন millis() >> 2; শুধু বিভক্ত করতে বললে কি খুব বেশি হত?
পল উইল্যান্ড

1
অপ্টিমাইজেশন -O3 সহ কর্টেক্স-এ 9 (যার কোনও হার্ডওয়্যার বিভাগ নেই) এর জন্য আমি জিসিসি-র বিরুদ্ধে i / 32বনাম i >> 5এবং i / 4বনাম পরীক্ষা i >> 2করেছি এবং ফলস্বরূপ সমাবেশটি হুবহু একই ছিল। আমি প্রথমে বিভাগগুলি ব্যবহার করতে পছন্দ করি না তবে এটি আমার উদ্দেশ্য বর্ণনা করে এবং আউটপুট একই।
রোববার

91

পরিমাপের একটি কংক্রিট পয়েন্ট: বহু বছর আগে, আমি আমার হ্যাশিং অ্যালগরিদমের দুটি সংস্করণ বেঞ্চমার্ক করেছি:

unsigned
hash( char const* s )
{
    unsigned h = 0;
    while ( *s != '\0' ) {
        h = 127 * h + (unsigned char)*s;
        ++ s;
    }
    return h;
}

এবং

unsigned
hash( char const* s )
{
    unsigned h = 0;
    while ( *s != '\0' ) {
        h = (h << 7) - h + (unsigned char)*s;
        ++ s;
    }
    return h;
}

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

নোট করুন যে এটি 15 বছর আগে কিছু ছিল। আশা করি, সংকলকরা তখন থেকে কেবল আরও ভাল অর্জন করেছেন, তাই আপনি সঠিকরূপে কম্পাইলারটির উপর নির্ভর করতে পারেন, আপনার চেয়ে সম্ভবত আরও ভাল। (এছাড়াও কোডটি সি'শ দেখানোর কারণটি হ'ল কারণ এটি 15 বছর পূর্বে ছিল I'd আমি স্পষ্টতই std::stringআজ এবং পুনরুক্তি ব্যবহার করতাম ))


5
আপনি নিম্নলিখিত ব্লগ পোস্টে আগ্রহী হতে পারেন, যেখানে লেখক নোট করেছেন যে আধুনিকীকরণের অপ্টিমাইজ করা সংকলকগুলিকে রিভার্স-ইঞ্জিনিয়ার সাধারণ প্যাটার্নগুলি মনে হয় যা প্রোগ্রামাররা তাদের গাণিতিক ফর্মগুলিতে আরও দক্ষতার চিন্তাভাবনা ব্যবহার করতে পারে যাতে সত্যই তাদের জন্য সবচেয়ে দক্ষ নির্দেশের অনুক্রম তৈরি করা যায় to । আকৃতির-code.coding- গাইডলাইনস
পাস্কেল কুয়াক

@ পাসলকুয়াক এই সম্পর্কে সত্যই নতুন কিছু নয়। আমি প্রায় 20 বছর আগে সান সিসির জন্য একই জিনিসটি আবিষ্কার করেছি।
জেমস কানজে

66

এখানে অন্যান্য সমস্ত ভাল উত্তর ছাড়াও, আমাকে বিভাজন বা গুণিত করার সময় শিফ্টটি ব্যবহার না করার জন্য আরও একটি কারণ উল্লেখ করতে দিন। গুণ এবং সংযোজনের আনুষ্ঠানিক নজরে ভুলে গিয়ে কেউ কখনও কোনও বাগ প্রবর্তন করতে দেখিনি। আমি বাগগুলি প্রবর্তিত দেখেছি যখন রক্ষণাবেক্ষণ প্রোগ্রামাররা ভুলে গিয়েছিলেন যে শিফটের মাধ্যমে " গুণমান " যুক্তিগতভাবে একটি গুণ, তবে সিনট্যাকটিকভাবে গুণের মতো একই নজির নয়। x * 2 + zএবং x << 1 + zখুব আলাদা!

আপনি যদি সংখ্যাগুলিতে কাজ করছেন তবে পাটিগণিত অপারেটরগুলি পছন্দ করুন + - * / %। আপনি যদি বিটের অ্যারেগুলিতে কাজ করছেন তবে বিট টুইডলিং অপারেটরগুলি পছন্দ করুন & ^ | >>। তাদের মিশ্রিত করবেন না; একটি এক্সপ্রেশন যা বিট টুইডলিং এবং গাণিতিক উভয়ই হ'ল একটি বাগ হওয়ার জন্য অপেক্ষা করছে।


5
সহজ বন্ধনী দিয়ে এড়ানো যায়?
জোয়েল বি

21
@ জোয়েল: অবশ্যই আপনি যদি মনে রাখেন যে আপনার তাদের প্রয়োজন। আমার বক্তব্যটি হ'ল আপনি যেটা করেন তা ভুলে যাওয়া সহজ। "X << 1" পড়ার মানসিক অভ্যাসে থাকা লোকেরা "x * 2" বলে মনে করার মানসিক অভ্যাসটি পান যে << গুণটির একই নজির, যা তা নয়।
এরিক লিপার্ট

1
ঠিক আছে, আমি "হাই * 256 + লো" এর চেয়ে বেশি অভিপ্রকাশ-প্রকাশ ("হাই << 8) + লো" খুঁজে পাই reve সম্ভবত এটি স্বাদের বিষয়, তবে কখনও কখনও বিট-টুইডলিং লিখতে আরও স্পষ্ট হয়। বেশিরভাগ ক্ষেত্রে যদিও আমি আপনার বক্তব্যের সাথে একমত হই।
ইভান ডানিলভ

32
@ ইভান: এবং "(হাই << 8) | লো" আরও স্পষ্ট। কিছুটা অ্যারের কম বিট সেট করা পূর্ণসংখ্যার যোগ নয় । এটি বিট সেট করছে , তাই বিট সেট করে এমন কোডটি লিখুন।
এরিক লিপার্ট

1
কি দারুন. এর আগে এভাবে ভাবিনি। ধন্যবাদ।
ইভান ডানিলভ

50

এটি প্রসেসর এবং সংকলকটির উপর নির্ভর করে। কিছু সংকলক ইতিমধ্যে কোডটিকে অপ্টিমাইজ করে, অন্যরা তা করে না। সুতরাং আপনার কোডটি এই সময়টি অপ্টিমাইজ করা দরকার প্রত্যেক সময় আপনাকে পরীক্ষা করা উচিত।

যদি না আপনি মরিয়া হয়ে অপ্টিমাইজ করতে চান তবে আমি কেবল কোনও সমাবেশ নির্দেশ বা প্রসেসর চক্রটি সংরক্ষণ করতে আমার উত্স কোডটি স্ক্র্যাম্ব করব না।


3
কেবল একটি মোটামুটি অনুমান যোগ করার জন্য: একটি সাধারণ 16-বিট প্রসেসরের (80 সি 166) তে দুটি ইন্ট যুক্ত 1-2 টি চক্র হয়, 10 চক্রের একটি গুণ এবং 20 চক্রের বিভাগ হয়। প্লাস কিছু সরানো-ক্রিয়াকলাপগুলি যদি আপনি একাধিক সংকেত (প্রতিটি মুভিতে অন্য +1 চক্র) করতে পারেন * সর্বাধিক প্রচলিত সংকলক (কেইল / টাস্কিং) 2 এর পাওয়ার দ্বারা গুণক / বিভাগগুলির জন্য অপ্টিমাইজ করে না
জেনস

55
এবং সাধারণভাবে, সংকলক কোডটি আপনার চেয়ে আরও ভাল।
ব্যবহারকারী 703016

আমি সম্মত হই যে "পরিমাণগুলিকে" গুণিত করার সময়, গুণটি অপারেটর সাধারণত ভাল হয় তবে 2 এর দ্বারা স্বাক্ষরিত মানগুলিকে ভাগ করার সময় >>অপারেটর দ্রুততর হয় /এবং স্বাক্ষরিত মানগুলি যদি negativeণাত্মক হতে পারে তবে এটি প্রায়শই শব্দার্থগতভাবেও উচ্চতর হয়। কারও যদি মানটির x>>4উত্পন্ন হয় তবে এটি তার থেকে অনেক বেশি পরিষ্কার x < 0 ? -((-1-x)/16)-1 : x/16;and
সুপারকেট

38

(I << 3) + (i << 1) আই * 10 সরাসরি ব্যবহারের চেয়ে 10 দিয়ে গুণিত করা কি আসলেই দ্রুত হয়?

এটি আপনার মেশিনে থাকতে পারে এবং নাও থাকতে পারে - যদি আপনি যত্ন নেন তবে আপনার আসল-বিশ্বের ব্যবহার পরিমাপ করুন।

একটি কেস স্টাডি - 486 থেকে কোর i7 পর্যন্ত

বেঞ্চমার্কিং অর্থপূর্ণভাবে করা খুব কঠিন, তবে আমরা কয়েকটি তথ্য দেখতে পারি। থেকে http://www.penguin.cz/~literakl/intel/s.html#SAL এবং http://www.penguin.cz/~literakl/intel/i.html#IMUL আমরা এক্স 86 ঘড়ি চক্র একটি ধারণা পেতে পাটিগণিত শিফট এবং গুণনের জন্য প্রয়োজন। বলুন আমরা "486" (সর্বশেষতম তালিকাভুক্ত), 32 বিট রেজিস্টার এবং তাত্ক্ষণিকভাবে আঁকড়ে থাকি, আইএমএল 13-42 চক্র এবং আইডিআইভি 44 নেয় Each প্রতিটি এসএএল 2 নেয়, এবং 1 যোগ করে, তাই এমনকি যারা একসাথে পৃষ্ঠপোষকভাবে চেহারা পরিবর্তন করছেন তাদের কয়েকটির সাথেও একটি বিজয়ীর মত।

মূল i7 সহ আজকাল:

( http://software.intel.com/en-us/forums/showthread.php?t=61481 থেকে )

বিলম্বটি পূর্ণসংখ্যা সংযোজনের জন্য 1 টি চক্র এবং পূর্ণসংখ্যার গুণনের জন্য 3 টি চক্র । আপনি ল্যাটেন্সি এবং thoughput এর পরিশিষ্ট C "হল Intel 64 এবং IA-32 আর্কিটেকচারের অপ্টিমাইজেশান রেফারেন্স ম্যানুয়াল", যা অবস্থিত অনুসন্ধান করতে পারেন http://www.intel.com/products/processor/manuals/

(কিছু ইনটেল ব্লার্ব থেকে)

এসএসই ব্যবহার করে, কোর আই 7 একযোগে সংযোজন এবং গুণাগুলির নির্দেশনা জারি করতে পারে, ফলস্বরূপ প্রতি ঘড়ির চক্রে 8 ভাসমান-পয়েন্ট অপারেশন (এফএলওপি) শীর্ষের হারের সৃষ্টি করে

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

উত্স কোড বনাম বাস্তবায়নে কার্যকারিতা

আরও সাধারণভাবে, আপনার প্রশ্নটিকে সি এবং সি ++ ট্যাগ করা হয়। তৃতীয় প্রজন্মের ভাষা হিসাবে, এগুলি নির্দিষ্টভাবে অন্তর্নিহিত সিপিইউ নির্দেশের সেটটির বিশদটি গোপন করার জন্য তৈরি করা হয়েছে। তাদের ভাষার মানগুলি পূরণ করার জন্য , অন্তর্নিহিত হার্ডওয়্যারটি না করলেও তাদের অবশ্যই গুণন এবং শিফটিং অপারেশনগুলি (এবং অনেকগুলি) সমর্থন করতে হবে । এই জাতীয় ক্ষেত্রে, তাদের অন্যান্য অনেক নির্দেশাবলী ব্যবহার করে প্রয়োজনীয় ফলাফল সংশ্লেষ করতে হবে ize একইভাবে, সিপিইউয়ের অভাব থাকলে এবং কোনও এফপিইউ না থাকলে তাদের অবশ্যই ভাসমান পয়েন্ট অপারেশনের জন্য সফ্টওয়্যার সহায়তা সরবরাহ করতে হবে। আধুনিক সিপিইউ সমস্ত সমর্থন করে* এবং<<, সুতরাং এটি অযৌক্তিক তাত্ত্বিক এবং historicalতিহাসিক মনে হতে পারে, তবে তাত্পর্যপূর্ণ বিষয়টি হ'ল বাস্তবায়ন বাছাই করার স্বাধীনতা উভয় পথে চলেছে: এমনকি সিপিইউতে এমন একটি নির্দেশ রয়েছে যা সাধারণ ক্ষেত্রে উত্স কোডে অনুরোধ করা অপারেশনটি প্রয়োগ করে, সংকলকটি বিনামূল্যে অন্য যেটিকে পছন্দ করে তা চয়ন করুন কারণ সংকলকটির যে নির্দিষ্ট ক্ষেত্রে এটির মুখোমুখি হয়েছিল তার পক্ষে এটি আরও ভাল ।

উদাহরণ (একটি অনুমানী সমাবেশের ভাষা সহ)

source           literal approach         optimised approach
#define N 0
int x;           .word x                xor registerA, registerA
x *= N;          move x -> registerA
                 move x -> registerB
                 A = B * immediate(0)
                 store registerA -> x
  ...............do something more with x...............

এক্সক্লুসিভ বা ( xor) এর মতো নির্দেশাবলীর উত্স কোডের সাথে কোনও সম্পর্ক নেই, তবে কোনও কিছু দিয়ে নিজের সাথে xor-ing করা সমস্ত বিট সাফ করে, তাই এটি 0 তে সেট করার জন্য ব্যবহার করা যেতে পারে Source উত্স কোড যা মেমরির ঠিকানাগুলি বোঝায় যে কোনও ব্যবহৃত হচ্ছে না।

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

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

Maintainability

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

ধন্যবাদ, জিসিসির মতো ভাল সংকলক সাধারণত যখন কোনও অপ্টিমাইজেশন সক্ষম করে (যেমন ...main(...) { return (argc << 4) + (argc << 2) + argc; }-> imull $21, 8(%ebp), %eax) সক্ষম হয় তখন সরাসরি গুনের সাথে বিট শিফট এবং পাটিগণিতগুলির একটি সিরিজ প্রতিস্থাপন করতে পারে তাই কোডটি সংশোধন না করে পুনরায় সংকলন এমনকি সহায়তা করতে পারে, তবে এটির নিশ্চয়তা নেই।

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

আংশিক সমাধান বনাম সাধারণ সমাধান

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

বিট অপারেটর ব্যবহার করে গুণ এবং বিভাগ অর্জন করা যায় ...

আপনি গুণের বর্ণনা দিচ্ছেন, তবে ভাগ কেটে যাবে?

int x;
x >> 1;   // divide by 2?

সি ++ স্ট্যান্ডার্ড 5.8 অনুযায়ী:

-৩- E1 >> E2 এর মান হ'ল E1 ডান স্থানান্তরিত E2 বিট অবস্থান। যদি E1 এর স্বাক্ষরবিহীন প্রকার থাকে বা E1 এর একটি স্বাক্ষরিত প্রকার এবং একটি ননজিগেটভেট মান রয়েছে, ফলাফলের মানটি E1 এর ভাগফলের অবিচ্ছেদ্য অংশ যা পাওয়ার E2 তে উত্পন্ন 2 পরিমাণ দ্বারা বিভক্ত হয়। যদি E1 এর একটি স্বাক্ষরিত ধরণ এবং negativeণাত্মক মান থাকে তবে ফলাফল মান বাস্তবায়ন সংজ্ঞায়িত হয়।

সুতরাং, আপনার বিট শিফটের একটি বাস্তবায়ন সংজ্ঞায়িত ফলাফল রয়েছে যখন xনেতিবাচক হয়: এটি বিভিন্ন মেশিনে একইভাবে কাজ করতে পারে না। তবে, /অনেক বেশি অনুমানযোগ্যভাবে কাজ করে। (এটি উভয়ই পুরোপুরি সামঞ্জস্যপূর্ণ নাও হতে পারে, কারণ বিভিন্ন মেশিনে নেতিবাচক সংখ্যার বিভিন্ন উপস্থাপনা থাকতে পারে এবং তাই একই রকম সংখ্যক বিট উপস্থাপনাটি তৈরি করার পরেও বিভিন্ন রেঞ্জ থাকে))

আপনি বলতে পারেন "আমি যত্ন করি না ... intএটি কর্মচারীর বয়স সংরক্ষণ করছে, এটি কখনও নেতিবাচক হতে পারে না"। যদি আপনার কাছে সেই ধরণের বিশেষ অন্তর্দৃষ্টি থাকে তবে হ্যাঁ - আপনার >>নিরাপদ অপ্টিমাইজেশন সংকলক দ্বারা আপনার কোডটিতে স্পষ্টভাবে না করা পর্যন্ত পার হতে পারে। তবে, এটি ঝুঁকিপূর্ণ এবং খুব কমই দরকারী যেমন আপনার এই ধরণের অন্তর্দৃষ্টি হবে না এবং একই কোডে কাজ করা অন্যান্য প্রোগ্রামাররা জানতে পারবেন না যে আপনি নিজের ডেটার কিছু অস্বাভাবিক প্রত্যাশা নিয়ে বাজি রেখেছেন ' হ্যান্ডলিং করব ... আপনার "অপ্টিমাইজেশন" এর কারণে তাদের সম্পূর্ণরূপে নিরাপদ পরিবর্তন ব্যাকফায়ার হতে পারে।

এমন কোনও ধরণের ইনপুট রয়েছে যা এইভাবে গুণ বা ভাগ করা যায় না?

হ্যাঁ ... উপরে উল্লিখিত হিসাবে, নেতিবাচক সংখ্যার বাস্তবায়ন সংজ্ঞায়িত আচরণ থাকে যখন বিট-শিফটিং দ্বারা "বিভক্ত" হয়।


2
খুব সুন্দর উত্তর। কোর আই vs বনাম ৪৮6 তুলনা আলোকিত!
ড্রু হল

সমস্ত সাধারণ স্থাপত্যগুলিতে, intVal>>1একই শব্দার্থক থাকবে যা intVal/2কখনও কখনও উপযোগী এমন উপায়ে পৃথক হয় । যদি কারও কাছে পোর্টেবল ফ্যাশনে গণনা করা প্রয়োজন যে সাধারণ স্থাপত্যগুলি যে মূল্য দেয় intVal >> 1, তার জন্য অভিব্যক্তিটি আরও জটিল এবং পড়ার পক্ষে আরও কঠোর হওয়া দরকার এবং এটি যেটির জন্য উত্পাদিত হয়েছে তাতে যথেষ্ট পরিমাণে নিকৃষ্ট কোড তৈরি করতে পারে intVal >> 1
সুপারক্যাট

35

এটি কেবল আমার মেশিনে সংকলনের চেষ্টা করেছিলাম:

int a = ...;
int b = a * 10;

বিযুক্ত করার সময় এটি আউটপুট উত্পাদন করে:

MOV EAX,DWORD PTR SS:[ESP+1C] ; Move a into EAX
LEA EAX,DWORD PTR DS:[EAX+EAX*4] ; Multiply by 5 without shift !
SHL EAX, 1 ; Multiply by 2 using shift

খাঁটি স্থানান্তর এবং সংযোজন সহ এই সংস্করণটি আপনার হ্যান্ড-অপ্টিমাইজড কোডের চেয়ে দ্রুত।

সংকলকটি কী ঘটতে চলেছে তা আপনি সত্যই জানেন না, তাই কেবল একটি সাধারণ গুণটি লেখাই ভাল এবং তিনি যেভাবে চান তার উপায়টিকে অনুকূল করতে দিন, যেখানে আপনি জানেন যে সংকলকটি অনুকূলিত করতে পারে না।


1
আপনি যদি ভেক্টরটির অংশটি এড়িয়ে যান তবে আপনি এটির জন্য একটি বড় উত্সাহ অর্জন করতে পারতেন। সংকলক যদি গুণটি ঠিক করতে পারে তবে এটি দেখতে পাবে যে ভেক্টরটি পরিবর্তন হয় না।
বো পারসন

কোনও সংকলক কীভাবে জানতে পারে যে কিছু ভ্যাক্টর অনুমান না করে কোনও ভেক্টরের আকার পরিবর্তন হবে না? বা আপনি কি কখনও সমঝোতার কথা শুনেন নি ...
চার্লস গুডউইন

1
ঠিক আছে, তাই আপনি কোনও লকবিহীন বৈশ্বিক ভেক্টরটি লুপ করবেন? এবং আমি কোনও স্থানীয় ভেক্টরকে লুপ করছি যার ঠিকানা নেওয়া হয়নি, এবং কেবল কনস্ট সদস্য সদস্যদের ফাংশন বলি। কমপক্ষে আমার সংকলক বুঝতে পেরেছে যে ভেক্টরের আকার পরিবর্তন হবে না। (এবং শীঘ্রই কেউ আমাদের চ্যাটিংয়ের জন্য ফ্ল্যাগ করবে :-))
বো পারসন

1
@ বুপারসন অবশেষে, এতক্ষণ পরে, আমি কম্পাইলারটি অপ্টিমাইজ করতে সক্ষম না হওয়া সম্পর্কে আমার বিবৃতি সরিয়ে ফেললাম vector<T>::size()। আমার সংকলকটি বেশ প্রাচীন ছিল! :)
ব্যবহারকারী 703016

21

বদলানো সাধারণত কোনও নির্দেশের স্তরে গুণনের চেয়ে অনেক দ্রুত হয় তবে আপনি অকাল অপটিমাইজেশন করে আপনার সময় নষ্ট করছেন। সংকলক সংকলনের সময় এই অপটিমাইজেশন ভাল করতে পারে। এটি নিজেই করা পাঠযোগ্যতার উপর প্রভাব ফেলবে এবং সম্ভবত কার্য সম্পাদনের উপর কোনও প্রভাব ফেলবে না। আপনি যদি প্রোফাইল তৈরি করে থাকেন এবং এটিকে কোনও বাধা হিসাবে খুঁজে পেয়ে থাকেন তবে এই জাতীয় কাজগুলি করার পক্ষে এটি কেবলমাত্র উপযুক্ত।

প্রকৃতপক্ষে বিভাগের কৌশল, 'ম্যাজিক বিভাগ' নামে পরিচিত আসলে প্রচুর পরিমাণে পারিশ্রমিক অর্জন করতে পারে। এটির দরকার আছে কিনা তা দেখতে আপনাকে প্রথমে প্রোফাইল করা উচিত। তবে আপনি যদি এটি ব্যবহার করেন তবে একই বিভাগ বিভাগটির জন্য কী নির্দেশাবলীর প্রয়োজন তা নির্ধারণ করতে আপনাকে চারপাশে দরকারী প্রোগ্রাম রয়েছে help এখানে একটি উদাহরণ: http://www.masm32.com/board/index.php?topic=12421.0

এমএএসএম 32 তে আমি ওপি'র থ্রেড থেকে উত্তোলনের একটি উদাহরণ:

include ConstDiv.inc
...
mov eax,9999999
; divide eax by 100000
cdiv 100000
; edx = quotient

উত্পন্ন হবে:

mov eax,9999999
mov edx,0A7C5AC47h
add eax,1
.if !CARRY?
    mul edx
.endif
shr edx,16

7
@ ড্র কিছু কারণে আপনার মন্তব্য আমাকে হাসতে এবং আমার কফি ছড়িয়ে দিয়েছিল। ধন্যবাদ।
asawyer

30
গণিত পছন্দ করার বিষয়ে কোনও এলোমেলো ফোরাম থ্রেড নেই। গণিত পছন্দ করে এমন যে কেউ জানেন যে সত্যিকারের "এলোমেলো" ফোরামের থ্রেড তৈরি করা কতটা কঠিন।
জোয়েল বি

1
এটা সম্ভবত এই মত কাজগুলি করার শুধুমাত্র এটা মূল্য যদি তুমি প্রোফাইল আছে এবং এই পাওয়া বোতলের হতে এবং আবার বিকল্প এবং প্রোফাইল বাস্তবায়িত অন্তত 10 বার কর্মক্ষমতা সুবিধা পাবেন
মিথ্যা রায়ান

12

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

পূর্ণসংখ্যা বিভাগ যদিও তুলনামূলকভাবে ধীরে ধীরে ধীরে ধীরে, তাই 2 এর শক্তির দ্বারা বিভাজনের পরিবর্তে একটি শিফট ব্যবহার করা এখনও একটি জয় এবং বেশিরভাগ সংকলক এটি অপ্টিমাইজেশন হিসাবে প্রয়োগ করবে। তবে নোট করুন যে এই অপ্টিমাইজেশানটি বৈধ হওয়ার জন্য লভ্যাংশটি হয় স্বাক্ষরবিহীন হওয়া দরকার বা ইতিবাচক হতে হবে। নেতিবাচক লভ্যাংশের জন্য শিফট এবং বিভাজন সমান নয়!

#include <stdio.h>

int main(void)
{
    int i;

    for (i = 5; i >= -5; --i)
    {
        printf("%d / 2 = %d, %d >> 1 = %d\n", i, i / 2, i, i >> 1);
    }
    return 0;
}

আউটপুট:

5 / 2 = 2, 5 >> 1 = 2
4 / 2 = 2, 4 >> 1 = 2
3 / 2 = 1, 3 >> 1 = 1
2 / 2 = 1, 2 >> 1 = 1
1 / 2 = 0, 1 >> 1 = 0
0 / 2 = 0, 0 >> 1 = 0
-1 / 2 = 0, -1 >> 1 = -1
-2 / 2 = -1, -2 >> 1 = -1
-3 / 2 = -1, -3 >> 1 = -2
-4 / 2 = -2, -4 >> 1 = -2
-5 / 2 = -2, -5 >> 1 = -3

সুতরাং আপনি যদি সংকলকটিকে সহায়তা করতে চান তবে নিশ্চিত হন যে লভ্যাংশের পরিবর্তনশীল বা এক্সপ্রেশনটি স্পষ্টভাবে স্বাক্ষরযুক্ত নয়।


4
পূর্ণসংখ্যা গুণগুলি প্লেস্টেশন 3 এর পিপিইউতে উদাহরণস্বরূপ মাইক্রোকোড হয় এবং পুরো পাইপলাইন স্টল করে। এটা কিছু প্ল্যাটফর্মের উপর তা বৃদ্ধি পায় পূর্ণসংখ্যা এখনও এড়াতে :) সুপারিশ করা হচ্ছে
Maister

2
অনেক স্বাক্ষরবিহীন বিভাগগুলি হ'ল - ধরে নেই যে সংকলক জানে - স্বাক্ষরযুক্ত স্বীকৃতিগুলি ব্যবহার করে কীভাবে কার্যকর করা হয়েছে। এক বা দুটি গুণ কয়েক @ কয়েক ঘড়ি চক্র প্রতিটি এবং 40 টি চক্র বিভাজন হিসাবে একই কাজ করতে পারে।
অলফ ফোর্শেল

1
@ অলফ: সত্য, তবে কেবল একটি সংকলন-সময় ধ্রুবক দ্বারা বিভাগের জন্য বৈধ
পল আর

4

এটি সম্পূর্ণরূপে লক্ষ্য ডিভাইস, ভাষা, উদ্দেশ্য ইত্যাদির উপর নির্ভর করে

ভিডিও কার্ড ড্রাইভারের মধ্যে পিক্সেল ক্রাঞ্চিং? খুব সম্ভবত, হ্যাঁ!

আপনার বিভাগের জন্য নেট ব্যবসায়ের আবেদন? একেবারে দেখার জন্যও কোনও কারণ নেই।

একটি মোবাইল ডিভাইসের জন্য উচ্চ পারফরম্যান্স গেমের জন্য এটি সন্ধানের পক্ষে মূল্যবান হতে পারে তবে কেবল সহজতর অপ্টিমাইজেশান সম্পাদন করার পরে।


2

আপনার একেবারে প্রয়োজন না হলে এবং আপনার কোডের অভিপ্রায়টির জন্য গুণ / বিভাগের পরিবর্তে পরিবর্তনের প্রয়োজন হয় না do

সাধারণ দিনে - আপনি সম্ভাব্য কয়েকটি মেশিন চক্র বাঁচাতে পারেন (বা আলগা, যেহেতু সংকলকটি আরও কী অনুকূল করতে হবে তা ভালভাবে জানে), তবে ব্যয়ের পক্ষে এটি মূল্য হয় না - আপনি কোডটি বজায় রাখার চেয়ে সামান্য বিবরণে সময় ব্যয় করেন, কোড বজায় রাখা আরও শক্ত হয়ে যায় এবং আপনার সহকর্মীরা আপনাকে অভিশাপ দেবে।

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


1

যতদূর আমি জানি কিছু মেশিনে গুণনের জন্য 16 থেকে 32 মেশিন চক্রের প্রয়োজন হতে পারে। তাই হ্যাঁ , মেশিন ধরনের উপর নির্ভর করে, bitshift অপারেটার দ্রুত গুণ / ভাগ চেয়ে আছে।

তবে নির্দিষ্ট মেশিনে তাদের গণিত প্রসেসর রয়েছে, যার মধ্যে গুণ / বিভাগের জন্য বিশেষ নির্দেশ রয়েছে।


7
এই মেশিনগুলির জন্য সংকলক লেখার লোকেরা সম্ভবত হ্যাকার্স ডিলাইট পড়েছে এবং সেই অনুসারে অনুকূলিত করেছে।
বো পারসন

1

আমি ড্রউ হলের চিহ্নিত উত্তরের সাথে একমত উত্তরটি যদিও অতিরিক্ত কিছু নোট ব্যবহার করতে পারে।

সফ্টওয়্যার বিপুল সংখ্যক বিকাশকারীদের জন্য প্রসেসর এবং সংকলক এখন আর প্রশ্নের সাথে প্রাসঙ্গিক নয়। আমাদের বেশিরভাগই ৮০৮৮ এবং এমএস-ডসের বাইরে are এটি সম্ভবত তাদের জন্য প্রাসঙ্গিক যারা এখনও এম্বেড থাকা প্রসেসরের জন্য বিকাশ করছেন ...

আমার সফ্টওয়্যার সংস্থাটিতে ম্যাথ (অ্যাড / সাব / মুল / ডিভি) সমস্ত গণিতের জন্য ব্যবহার করা উচিত। তথ্য প্রকারের মধ্যে রূপান্তর করার সময় শিফ্ট ব্যবহার করা উচিত যেমন উদা। বাইট হিসাবে এন >> 8 এবং এন / 256 নয় us


আমিও আপনার সাথে একমত আমি অবচেতনভাবে একই গাইডলাইনটি অনুসরণ করি, যদিও এর আগে কখনও আমার আনুষ্ঠানিক প্রয়োজন হয় নি।
ড্রয় হল

0

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


বা নম্বরটি নিক্ষেপ করুনunsigned
লাই রিয়ান

4
আপনি কি নিশ্চিত যে স্থানান্তরিত আচরণটি মানকৃত? আমি এই ধারণার মধ্যে ছিলাম যে নেতিবাচক ints উপর ডান শিফট বাস্তবায়ন সংজ্ঞায়িত হয়।
কেরেক এসবি

1
যদিও আপনার সম্ভবত সেই কোডটি উল্লেখ করা উচিত যা ডান-শিফটিং নেতিবাচক সংখ্যার জন্য কোনও নির্দিষ্ট আচরণের উপর নির্ভর করে, সেই প্রয়োজনীয়তার নথিটি দেওয়া উচিত, ডান-শিফটিংয়ের সুবিধা এমন ক্ষেত্রে বড় হয় যেখানে প্রাকৃতিকভাবে সঠিক মান পাওয়া যায় এবং বিভাগ অপারেটর নষ্ট করার কোড তৈরি করে একটি অযাচিত মান গণনা করার সময় ব্যবহারকারী কোডটি প্রথমে শিফ্টটি যা দেবে তা নির্ধারণের জন্য অতিরিক্ত সময় নষ্ট করতে হবে। আসলে, আমার যদি আমার ড্রথার থাকে, সংকলকদের স্বাক্ষরিত বিভাগ সম্পাদনের চেষ্টা করার কারণে ঝাঁকুনির বিকল্প ছিল, যেহেতু ...
সুপারক্যাট

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

0

পাইথন পরীক্ষা একই র‌্যান্ডম সংখ্যার বিপরীতে 100 মিলিয়ন বার একই গুণ করে performing

>>> from timeit import timeit
>>> setup_str = 'import scipy; from scipy import random; scipy.random.seed(0)'
>>> N = 10*1000*1000
>>> timeit('x=random.randint(65536);', setup=setup_str, number=N)
1.894096851348877 # Time from generating the random #s and no opperati

>>> timeit('x=random.randint(65536); x*2', setup=setup_str, number=N)
2.2799630165100098
>>> timeit('x=random.randint(65536); x << 1', setup=setup_str, number=N)
2.2616429328918457

>>> timeit('x=random.randint(65536); x*10', setup=setup_str, number=N)
2.2799630165100098
>>> timeit('x=random.randint(65536); (x << 3) + (x<<1)', setup=setup_str, number=N)
2.9485139846801758

>>> timeit('x=random.randint(65536); x // 2', setup=setup_str, number=N)
2.490908145904541
>>> timeit('x=random.randint(65536); x / 2', setup=setup_str, number=N)
2.4757170677185059
>>> timeit('x=random.randint(65536); x >> 1', setup=setup_str, number=N)
2.2316000461578369

সুতরাং পাইথনে দু'জনের পাওয়ার দ্বারা গুণ / বিভাগের পরিবর্তে একটি শিফ্ট করার ক্ষেত্রে কিছুটা উন্নতি হয়েছে (বিভাগের জন্য 10% ডলার; গুণণের জন্য 1%)। যদি এটি দু'জনের অ-শক্তি হয়, তবে সম্ভবত যথেষ্ট ধীরগতি দেখা দেবে।

আবার এই # টি আপনার প্রসেসরের উপর নির্ভর করে পরিবর্তিত হবে, আপনার সংকলক (বা দোভাষী - সরলতার জন্য অজগরটি করেছিলেন)।

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


0

সংকলকটি করতে পারে না এমন অপ্টিমাইজেশন রয়েছে কারণ তারা কেবল ইনপুটগুলির একটি হ্রাস সেট জন্য কাজ করে।

নীচে সি ++ স্যাম্পল কোড রয়েছে যা একটি 64 বিটস "পারস্পরিকভাবে গুণিত" দ্বারা দ্রুততর বিভাগ করতে পারে doing অংক এবং ডিনোমিনেটর উভয়ই অবশ্যই নির্দিষ্ট প্রান্তিকের নীচে থাকতে হবে। নোট করুন যে এটি অবশ্যই স্বাভাবিক বিভাগের চেয়ে দ্রুত হওয়ার জন্য 64 বিট নির্দেশাবলী ব্যবহার করতে সংকলিত করতে হবে।

#include <stdio.h>
#include <chrono>

static const unsigned s_bc = 32;
static const unsigned long long s_p = 1ULL << s_bc;
static const unsigned long long s_hp = s_p / 2;

static unsigned long long s_f;
static unsigned long long s_fr;

static void fastDivInitialize(const unsigned d)
{
    s_f = s_p / d;
    s_fr = s_f * (s_p - (s_f * d));
}

static unsigned fastDiv(const unsigned n)
{
    return (s_f * n + ((s_fr * n + s_hp) >> s_bc)) >> s_bc;
}

static bool fastDivCheck(const unsigned n, const unsigned d)
{
    // 32 to 64 cycles latency on modern cpus
    const unsigned expected = n / d;

    // At least 10 cycles latency on modern cpus
    const unsigned result = fastDiv(n);

    if (result != expected)
    {
        printf("Failed for: %u/%u != %u\n", n, d, expected);
        return false;
    }

    return true;
}

int main()
{
    unsigned result = 0;

    // Make sure to verify it works for your expected set of inputs
    const unsigned MAX_N = 65535;
    const unsigned MAX_D = 40000;

    const double ONE_SECOND_COUNT = 1000000000.0;

    auto t0 = std::chrono::steady_clock::now();
    unsigned count = 0;
    printf("Verifying...\n");
    for (unsigned d = 1; d <= MAX_D; ++d)
    {
        fastDivInitialize(d);
        for (unsigned n = 0; n <= MAX_N; ++n)
        {
            count += !fastDivCheck(n, d);
        }
    }
    auto t1 = std::chrono::steady_clock::now();
    printf("Errors: %u / %u (%.4fs)\n", count, MAX_D * (MAX_N + 1), (t1 - t0).count() / ONE_SECOND_COUNT);

    t0 = t1;
    for (unsigned d = 1; d <= MAX_D; ++d)
    {
        fastDivInitialize(d);
        for (unsigned n = 0; n <= MAX_N; ++n)
        {
            result += fastDiv(n);
        }
    }
    t1 = std::chrono::steady_clock::now();
    printf("Fast division time: %.4fs\n", (t1 - t0).count() / ONE_SECOND_COUNT);

    t0 = t1;
    count = 0;
    for (unsigned d = 1; d <= MAX_D; ++d)
    {
        for (unsigned n = 0; n <= MAX_N; ++n)
        {
            result += n / d;
        }
    }
    t1 = std::chrono::steady_clock::now();
    printf("Normal division time: %.4fs\n", (t1 - t0).count() / ONE_SECOND_COUNT);

    getchar();
    return result;
}

0

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

আমি এখনই কিছু কোড লিখছি যার জন্য প্রচুর দ্বিগুণ / অর্ধনমিত অপারেশন প্রয়োজন কারণ এটি ঘন বাইনারি গাছের উপর কাজ করছে, এবং আমার আরও সন্দেহ আছে যে সংযোজনের চেয়ে আরও অনুকূল হতে পারে - একটি বাম (দুই গুণকের শক্তি) ) একটি সংযোজন সঙ্গে শিফট। আপনি যে বিট যুক্ত করতে চান বিটের সংখ্যার চেয়ে শিফটটি প্রশস্ত হলে এটি একটি বাম শিফট এবং একটি জোর দিয়ে প্রতিস্থাপন করা যেতে পারে, উদাহরণস্বরূপ (i << 1) ^ 1, যা একটিকে দ্বিগুণ মান হিসাবে যুক্ত করে। এটি অবশ্যই ডান শিফটে (দুটি বিভাজনের শক্তি) প্রযোজ্য নয় কারণ কেবল একটি বাম (সামান্য এন্ডিয়ান) শিফট শূন্যের সাথে শূন্যস্থান পূরণ করে।

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

এছাড়াও, আমি যে অ্যালগরিদমগুলি লিখছি সেগুলিতে তারা চলাচল করে এমন আন্দোলনগুলি উপস্থাপন করে যাতে এই অর্থে তারা আসলে আরও স্পষ্ট। বাইনারি গাছের বাম দিকটি আরও বড় এবং ডানটি আরও ছোট। পাশাপাশি, আমার কোড অনুসারে বিজোড় এবং এমনকি সংখ্যার একটি বিশেষ তাত্পর্য রয়েছে এবং গাছের সমস্ত বাম-হাতের বাচ্চারা বিজোড় এবং ডান হাতের সমস্ত শিশু এবং মূলও সমান। কিছু ক্ষেত্রে, যা আমি এখনও মুখোমুখি হই নি, তবে ওহ, আসলে, আমি এমনকি এটি সম্পর্কে ভাবিনি, x & 1 এক্স% 2 এর তুলনায় আরও অনুকূল অপারেশন হতে পারে। সমান সংখ্যার x এবং 1 শূন্য উত্পাদন করবে তবে বিজোড় সংখ্যার জন্য 1 উত্পাদন করবে।

মাত্র বিজোড় / এমনকি সনাক্তকরণের চেয়ে কিছুটা এগিয়ে যাওয়া, যদি আমি এক্স ও 3 এর জন্য শূন্য পাই তবে আমি জানি যে 4 আমাদের সংখ্যার একটি ফ্যাক্টর, এবং 8% এর জন্য x% 7 এর জন্য একই। আমি জানি যে এই কেসগুলি সম্ভবত সীমিত উপযোগিতা পেয়েছে তবে এটি জেনে ভাল লাগল যে আপনি একটি মডুলাস অপারেশন এড়াতে পারেন এবং পরিবর্তে একটি বিটওয়াইজ লজিক অপারেশন ব্যবহার করতে পারেন, কারণ বিটওয়াইজ অপারেশনগুলি প্রায় সবসময় দ্রুত হয় এবং কমপায়ারটি সংকলকের কাছে অস্পষ্ট হওয়ার সম্ভাবনা থাকে।

আমি ঘন বাইনারি গাছের ক্ষেত্রটি বেশ উদ্ভাবন করছি তাই আমি প্রত্যাশা করি যে লোকেরা এই মন্তব্যের মূল্য উপলব্ধি করতে পারে না, খুব কমই লোকে কেবলমাত্র দু'জনের ক্ষমতার উপর ভিত্তি করে বা কেবল দুটিকে দু'টির গুণিত / ভাগ করতে চায়।



0

আপনি যদি কোনও জিসিসি সংকলকটিতে x + x, x * 2 এবং x << 1 সিনট্যাক্সের জন্য আউটপুট তুলনা করেন, তবে আপনি x86 সমাবেশে একই ফলাফল পাবেন: https://godbolt.org/z/JLpp0j

        push    rbp
        mov     rbp, rsp
        mov     DWORD PTR [rbp-4], edi
        mov     eax, DWORD PTR [rbp-4]
        add     eax, eax
        pop     rbp
        ret

সুতরাং আপনি যা টাইপ করেছেন তার থেকে স্বাধীনভাবে নিজের সেরা সমাধান নির্ধারণ করতে আপনি জিসিিকে স্মার্ট হিসাবে বিবেচনা করতে পারেন ।


0

আমিও দেখতে চেয়েছিলাম আমি হাউসকে বীট করতে পারি কিনা। এটি কোনও সংখ্যার গুণনের দ্বারা কোনও সংখ্যার জন্য আরও সাধারণ বিটওয়াইজ। আমি যে ম্যাক্রোগুলি তৈরি করেছি তা সাধারণ * গুণণের থেকে প্রায় 25% বেশি দ্বিগুণ er অন্যরা যেমন বলেছিল এটি যদি 2 এর একাধিকের নিকটে বা 2 এর কয়েকটি গুণক দিয়ে তৈরি হয় তবে আপনি জিততে পারেন। এক্স * 23 এর মতো তৈরি (এক্স << 4) + (এক্স << 2) + (এক্স << 1) + এক্স ধীর হতে চলেছে তখন এক্স * 65 (এক্স <<< 6) + এক্স দিয়ে তৈরি।

#include <stdio.h>
#include <time.h>

#define MULTIPLYINTBYMINUS(X,Y) (-((X >> 30) & 1)&(Y<<30))+(-((X >> 29) & 1)&(Y<<29))+(-((X >> 28) & 1)&(Y<<28))+(-((X >> 27) & 1)&(Y<<27))+(-((X >> 26) & 1)&(Y<<26))+(-((X >> 25) & 1)&(Y<<25))+(-((X >> 24) & 1)&(Y<<24))+(-((X >> 23) & 1)&(Y<<23))+(-((X >> 22) & 1)&(Y<<22))+(-((X >> 21) & 1)&(Y<<21))+(-((X >> 20) & 1)&(Y<<20))+(-((X >> 19) & 1)&(Y<<19))+(-((X >> 18) & 1)&(Y<<18))+(-((X >> 17) & 1)&(Y<<17))+(-((X >> 16) & 1)&(Y<<16))+(-((X >> 15) & 1)&(Y<<15))+(-((X >> 14) & 1)&(Y<<14))+(-((X >> 13) & 1)&(Y<<13))+(-((X >> 12) & 1)&(Y<<12))+(-((X >> 11) & 1)&(Y<<11))+(-((X >> 10) & 1)&(Y<<10))+(-((X >> 9) & 1)&(Y<<9))+(-((X >> 8) & 1)&(Y<<8))+(-((X >> 7) & 1)&(Y<<7))+(-((X >> 6) & 1)&(Y<<6))+(-((X >> 5) & 1)&(Y<<5))+(-((X >> 4) & 1)&(Y<<4))+(-((X >> 3) & 1)&(Y<<3))+(-((X >> 2) & 1)&(Y<<2))+(-((X >> 1) & 1)&(Y<<1))+(-((X >> 0) & 1)&(Y<<0))
#define MULTIPLYINTBYSHIFT(X,Y) (((((X >> 30) & 1)<<31)>>31)&(Y<<30))+(((((X >> 29) & 1)<<31)>>31)&(Y<<29))+(((((X >> 28) & 1)<<31)>>31)&(Y<<28))+(((((X >> 27) & 1)<<31)>>31)&(Y<<27))+(((((X >> 26) & 1)<<31)>>31)&(Y<<26))+(((((X >> 25) & 1)<<31)>>31)&(Y<<25))+(((((X >> 24) & 1)<<31)>>31)&(Y<<24))+(((((X >> 23) & 1)<<31)>>31)&(Y<<23))+(((((X >> 22) & 1)<<31)>>31)&(Y<<22))+(((((X >> 21) & 1)<<31)>>31)&(Y<<21))+(((((X >> 20) & 1)<<31)>>31)&(Y<<20))+(((((X >> 19) & 1)<<31)>>31)&(Y<<19))+(((((X >> 18) & 1)<<31)>>31)&(Y<<18))+(((((X >> 17) & 1)<<31)>>31)&(Y<<17))+(((((X >> 16) & 1)<<31)>>31)&(Y<<16))+(((((X >> 15) & 1)<<31)>>31)&(Y<<15))+(((((X >> 14) & 1)<<31)>>31)&(Y<<14))+(((((X >> 13) & 1)<<31)>>31)&(Y<<13))+(((((X >> 12) & 1)<<31)>>31)&(Y<<12))+(((((X >> 11) & 1)<<31)>>31)&(Y<<11))+(((((X >> 10) & 1)<<31)>>31)&(Y<<10))+(((((X >> 9) & 1)<<31)>>31)&(Y<<9))+(((((X >> 8) & 1)<<31)>>31)&(Y<<8))+(((((X >> 7) & 1)<<31)>>31)&(Y<<7))+(((((X >> 6) & 1)<<31)>>31)&(Y<<6))+(((((X >> 5) & 1)<<31)>>31)&(Y<<5))+(((((X >> 4) & 1)<<31)>>31)&(Y<<4))+(((((X >> 3) & 1)<<31)>>31)&(Y<<3))+(((((X >> 2) & 1)<<31)>>31)&(Y<<2))+(((((X >> 1) & 1)<<31)>>31)&(Y<<1))+(((((X >> 0) & 1)<<31)>>31)&(Y<<0))
int main()
{
    int randomnumber=23;
    int randomnumber2=23;
    int checknum=23;
    clock_t start, diff;
    srand(time(0));
    start = clock();
    for(int i=0;i<1000000;i++)
    {
        randomnumber = rand() % 10000;
        randomnumber2 = rand() % 10000;
        checknum=MULTIPLYINTBYMINUS(randomnumber,randomnumber2);
        if (checknum!=randomnumber*randomnumber2)
        {
            printf("s %i and %i and %i",checknum,randomnumber,randomnumber2);
        }
    }
    diff = clock() - start;
    int msec = diff * 1000 / CLOCKS_PER_SEC;
    printf("MULTIPLYINTBYMINUS Time %d milliseconds", msec);
    start = clock();
    for(int i=0;i<1000000;i++)
    {
        randomnumber = rand() % 10000;
        randomnumber2 = rand() % 10000;
        checknum=MULTIPLYINTBYSHIFT(randomnumber,randomnumber2);
        if (checknum!=randomnumber*randomnumber2)
        {
            printf("s %i and %i and %i",checknum,randomnumber,randomnumber2);
        }
    }
    diff = clock() - start;
    msec = diff * 1000 / CLOCKS_PER_SEC;
    printf("MULTIPLYINTBYSHIFT Time %d milliseconds", msec);
    start = clock();
    for(int i=0;i<1000000;i++)
    {
        randomnumber = rand() % 10000;
        randomnumber2 = rand() % 10000;
        checknum= randomnumber*randomnumber2;
        if (checknum!=randomnumber*randomnumber2)
        {
            printf("s %i and %i and %i",checknum,randomnumber,randomnumber2);
        }
    }
    diff = clock() - start;
    msec = diff * 1000 / CLOCKS_PER_SEC;
    printf("normal * Time %d milliseconds", msec);
    return 0;
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.