পূর্ণসংখ্যা বিভাগ বাস্তবায়নে জিসিসি কেন একটি অদ্ভুত সংখ্যার দ্বারা গুণ ব্যবহার করে?


227

আমি divএবং mulসমাবেশের কাজগুলি পড়ছি এবং সি তে একটি সাধারণ প্রোগ্রাম লিখে তাদের কার্যকরভাবে দেখার সিদ্ধান্ত নিয়েছি:

ফাইল বিভাগ

#include <stdlib.h>
#include <stdio.h>

int main()
{
    size_t i = 9;
    size_t j = i / 5;
    printf("%zu\n",j);
    return 0;
}

এবং তারপরে এ্যাসেম্বলি ভাষার কোড তৈরি করা:

gcc -S division.c -O0 -masm=intel

তবে উত্পন্ন division.sফাইলটি দেখলে এতে কোনও ডিভ অপারেশন নেই! পরিবর্তে, এটি বিট শিফটিং এবং ম্যাজিক সংখ্যাগুলির সাথে একরকম কালো যাদু করে। এখানে একটি কোড স্নিপেট যা গণনা করে i/5:

mov     rax, QWORD PTR [rbp-16]   ; Move i (=9) to RAX
movabs  rdx, -3689348814741910323 ; Move some magic number to RDX (?)
mul     rdx                       ; Multiply 9 by magic number
mov     rax, rdx                  ; Take only the upper 64 bits of the result
shr     rax, 2                    ; Shift these bits 2 places to the right (?)
mov     QWORD PTR [rbp-8], rax    ; Magically, RAX contains 9/5=1 now, 
                                  ; so we can assign it to j

এখানে কি হচ্ছে? জিসিসি কেন মোটেও ডিভ ব্যবহার করে না? এটি কীভাবে এই যাদু নম্বরটি তৈরি করে এবং কেন সমস্ত কিছু কাজ করে?


29
জিসিসি ধ্রুবক দ্বারা বিভাগগুলি অনুকূল করে তোলে, 2,3,4,5,6,7,8 দ্বারা বিভাগগুলি চেষ্টা করুন এবং আপনি সম্ভবত প্রতিটি ক্ষেত্রে খুব আলাদা কোড দেখতে পাবেন।
জ্যাবারওয়াকি

28
দ্রষ্টব্য: যাদু সংখ্যাটি একটি বা কেবল (2 ^ 64) * -36893488147419103234/5 CCCCCCCCCCCCCCCDহিসাবে রূপান্তর করে uint64_t
chux - মনিকা পুনরায় স্থাপন

32
@ কিউবিট: সংযোজকটি কেবল অপ্টিমাইজেশান অক্ষম থাকায় বিকলভাবে অক্ষম কোড তৈরি করবে না। একটি তুচ্ছ "অপ্টিমাইজেশন" যা কোড পুনর্নির্মাণের সাথে জড়িত না বা ভেরিয়েবল নির্মূলকরণ জড়িত না উদাহরণস্বরূপ নির্বিশেষে সম্পাদিত হবে। মূলত একক উত্স বিবৃতি বিচ্ছিন্নভাবে সেই অপারেশনটির জন্য সবচেয়ে কার্যকর কোডে অনুবাদ করবে। সংকলক অপ্টিমাইজেশান আশেপাশের কোডের পরিবর্তে কেবলমাত্র একক বিবৃতি গ্রহণ করে।
ক্লিফোর্ড

20
দুর্দান্ত এই নিবন্ধটি পড়ুন: বিভাগের শ্রম
জেসেটার

9
কিছু সংকলক আসলে বিকৃতভাবে অক্ষম কোড উত্পন্ন করবে কারণ অপ্টিমাইজেশন অক্ষম। বিশেষত, তারা পৃথক কোডের লাইনগুলিতে ব্রেকপয়েন্ট স্থাপন করার দক্ষতার মতো ডিবাগিং সহজ করার জন্য তারা এটি করবে। জিসিসি প্রকৃতপক্ষে বরং অস্বাভাবিক কারণ এতে সত্যিকারের "কোনও অপ্টিমাইজেশন" মোড নেই, কারণ এর অনেকগুলি অনুকূলিতকরণ গঠনমূলকভাবে চালু রয়েছে tive এটি আপনি জিসিসির সাথে দেখতে পাচ্ছেন এমন একটি উদাহরণ। অন্যদিকে ঝনঝন, এবং এমএসভিসি একটি নির্দেশ প্রকাশ করবে । (সিসি @ ক্লিফোর্ড)div-O0
কোডি গ্রে

উত্তর:


169

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

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

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

ফলস্বরূপ, সংকলনকালে বিভাজনটি জানা না থাকলে আপনি কেবল দেখতে divবা idivআউটপুটে দেখতে ঝোঁক ।

সংকলক কীভাবে এই সিকোয়েন্সগুলি জেনারেট করে তার পাশাপাশি তথ্যের জন্য আপনার নিজের জন্য এগুলি উত্পন্ন করতে কোড (আপনি অবশ্যই ব্র্যান্ডিনড সংকলকের সাথে কাজ না করেই প্রায় অপ্রয়োজনীয়), লিবিডিভাইড দেখুন


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

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

6
আসল উত্তরটি হ'ল gcc -O0 এখনও সিটিকে মেশিন কোডে পরিণত করার অংশ হিসাবে অভ্যন্তরীণ উপস্থাপনার মাধ্যমে কোডকে রূপান্তর করে । এটি কেবল ঘটে যায় যে মডিউলার গুণক বিপরীতগুলি ডিফল্টরূপে সক্ষম করা হয়েছে -O0(তবে এর সাথে নয় -Os)। অন্যান্য সংকলক (ঝাঁকুনির মতো) তে নন-পাওয়ার-অফ -2 ধ্রুবকের জন্য ডিআইভি ব্যবহার করবে -O0। সম্পর্কিত: আমি মনে করি আমি আমার কোলাটজ-অনুমানের হাতে লেখা এএসএম উত্তরে
পিটার কর্ডেস

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

9
@ স্নেফটেল: সম্ভবত এটি সম্ভবত কারণ অ্যাপ্লিকেশন বিকাশকারী যারা সংস্থার বিকাশকারীদের তাদের কোডটি প্রত্যাশার চেয়ে দ্রুত চলমান সম্পর্কে সক্রিয়ভাবে অভিযোগ করে তাদের সংখ্যা তুলনামূলকভাবে কম।
dan04

121

5 দ্বারা ভাগ করা 1/5 গুণ করা সমান, যা আবার 4/5 দ্বারা গুণিত করা এবং ডান 2 বিট স্থানান্তর করার সমান। সম্পর্কিত মান CCCCCCCCCCCCCCCDহেক্সে, যা হেক্সাডেসিমাল পয়েন্টের পরে রাখলে 4/5 এর বাইনারি উপস্থাপনা হয় (অর্থাত্ চার পঞ্চমাংশের বাইনারি 0.110011001100পুনরাবৃত্তি হয় - এর জন্য নীচে দেখুন)। আমি মনে করি আপনি এখান থেকে নিতে পারেন! আপনি স্থির পয়েন্ট গণিত পরীক্ষা করে দেখতে চাইতে পারেন (তবে নোট করুন এটি শেষের দিকে একটি পূর্ণসংখ্যার সাথে বৃত্তাকার হয়)।

কেন হিসাবে, ভাগের চেয়ে গুণগুলি দ্রুত এবং যখন বিভাজকটি স্থির করা হয়, এটি একটি দ্রুততর রুট।

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

আসুন এক মিনিটের জন্য বিবেচনা করা যাক কেন 0.CCCCCCCC...(হেক্স) বা 0.110011001100...বাইনারি 4/5 হয়। বাইনারি প্রতিনিধিত্বকে 4 দ্বারা বিভক্ত করুন (ডানদিকে 2 টি স্থান স্থানান্তর করুন), এবং আমরা 0.001100110011...যা করব তুচ্ছ পরিদর্শন দ্বারা প্রাপ্ত করার জন্য মূলটি যুক্ত করা যেতে পারে 0.111111111111..., যা স্পষ্টতই 1 এর সমান, দশমিকভাবে একইভাবে 0.9999999...একের সমান। অতএব, আমরা জানি যে x + x/4 = 1, তাই 5x/4 = 1, x=4/5। এরপরে এটি CCCCCCCCCCCCDরাউন্ডিংয়ের জন্য হেক্স হিসাবে উপস্থাপিত হয় (যেহেতু বাইনারি অঙ্কটি শেষের একের বাইরে উপস্থিত হবে 1)।


2
@ ব্যবহারকারী 2357112 আপনার নিজের উত্তর পোস্ট করতে নির্দ্বিধায়, কিন্তু আমি সম্মত নই। আপনি একটি 128 বিট স্থির পয়েন্ট উত্তর প্রদান করে 0.64 বিট দ্বারা 64.0 বিট হিসাবে গুণিত হিসাবে ভাবতে পারেন, যার মধ্যে সর্বনিম্ন b৪ বিট ফেলে দেওয়া হয়, তারপরে ৪ দ্বারা বিভাজন (যেমন আমি প্রথম প্যারায় দেখিয়েছি)। আপনি সম্ভবত একটি বিকল্প মডুলার গাণিতিক উত্তর নিয়ে আসতে সক্ষম হবেন যা বিট মুভমেন্টগুলিকে সমানভাবে ব্যাখ্যা করে, তবে আমি নিশ্চিত যে এটি ব্যাখ্যা হিসাবে কাজ করে।
16:36

6
মানটি আসলে "সিসিসিসিসিসিসিসিসিসিসিসিসিসিসিসিসিডি" "সর্বশেষ ডিটি গুরুত্বপূর্ণ, এটি নিশ্চিত করে যে ফলাফলটি যখন কাটা হয় তখন সঠিক বিভাগগুলি সঠিক উত্তর নিয়ে আসে।
প্লাগওয়াশ

4
কিছু মনে করো না. আমি দেখতে পাইনি যে তারা 128-বিটের গুণনের ফলাফলের উপরের b৪ বিট নিচ্ছে; এটি বেশিরভাগ ভাষায় আপনি করতে পারেন এমন কিছু নয়, তাই আমি প্রথমে বুঝতে পারি নি যে এটি ঘটছে। এই উত্তরটি কীভাবে 128-বিটের ফলাফলের উপরের 64 বিটগুলি স্থির-পয়েন্ট সংখ্যা দ্বারা গুণ করা এবং গোলাকারকে সমান করে তার স্পষ্ট উল্লেখ দ্বারা আরও উন্নত হবে improved (এছাড়াও, এটি কেন 1/5 এর পরিবর্তে 4/5 হতে হবে, এবং কেন নীচের পরিবর্তে 4/5 আপ করতে হবে তা ব্যাখ্যা করা ভাল))
ব্যবহারকারী 2357112

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

3
প্রকৃতপক্ষে আপনাকে সম্ভবত 5 টি সর্বোচ্চ সম্ভাব্য ইনপুট মানগুলি পরীক্ষা করতে হবে, যদি সঠিকভাবে অন্য সমস্ত কিছু করা উচিত।
প্লাগওয়াশ

60

সাধারণভাবে বিভাগের তুলনায় গুণ বহুগুণ। সুতরাং আমরা যদি এর পরিবর্তে পারস্পরিক ক্রিয়াকলাপের সাথে গুণ করতে পারি তবে আমরা একটি ধ্রুবক দ্বারা উল্লেখযোগ্যভাবে বিভাগকে গতিতে পারি

একটি বলি হ'ল আমরা একে অপরকে যথাযথভাবে প্রতিনিধিত্ব করতে পারি না (যদি না ভাগ দুটি দ্বারা হয় তবে সে ক্ষেত্রে আমরা সাধারণত বিভাগটিকে কিছুটা শিফটে রূপান্তর করতে পারি)। সুতরাং সঠিক উত্তরগুলি নিশ্চিত করতে আমাদের সতর্ক থাকতে হবে যে আমাদের পারস্পরিক ক্ষতিতে ত্রুটি আমাদের চূড়ান্ত ফলাফলের ত্রুটি না ঘটায়।

-3689348814741910323 হল 0xCCCCCCCCCCCCCCCDCD যা 0.64 নির্দিষ্ট পয়েন্টে প্রকাশিত 4/5 এরও বেশি মূল্য।

যখন আমরা একটি bit৪ বিট পূর্ণসংখ্যাকে ০..6৪ ফিক্সড পয়েন্ট সংখ্যা দিয়ে গুণ করি তখন আমরা একটি 64৪..6৪ ফলাফল পাই। আমরা মানটি একটি 64-বিট পূর্ণসংখ্যায় কাটা (কার্যকরভাবে এটি শূন্যের দিকে গোল করে) এবং তারপরে আরও একটি শিফট করান যা চারটি এবং আবার কেটে যায় বিট স্তরটি দেখে এটি স্পষ্ট হয় যে আমরা উভয় কাটকে একক কাটা হিসাবে বিবেচনা করতে পারি।

এটি স্পষ্টত আমাদের কমপক্ষে 5 দ্বারা বিভাজনের একটি সংলগ্নতা দেয় তবে এটি আমাদের শূন্যের দিকে সঠিকভাবে গোল করে একটি সঠিক উত্তর দেয়?

একটি সঠিক উত্তর পেতে ত্রুটিটি যথেষ্ট ছোট হওয়া দরকার উত্তরটি গোলাকার সীমানা পেরোনোর ​​জন্য নয়।

5 দ্বারা বিভাজনের সঠিক উত্তরটি সর্বদা 0, 1/5, 2/5, 3/5 বা 4/5 এর ভগ্নাংশ হতে পারে। সুতরাং গুণিত এবং স্থানান্তরিত ফলাফলের মধ্যে 1/5 এরও কম ইতিবাচক ত্রুটি ফলাফলকে কখনই বৃত্তাকার সীমানার উপরে চাপ দেয় না।

আমাদের ধ্রুবকটিতে ত্রুটিটি হল (1/5) * 2 -64I এর মান 2 64 এরও কম তাই গুণনের পরে ত্রুটি 1/5 এর চেয়ে কম। 4 দ্বারা বিভাজনের পরে ত্রুটি (1/5) * 2 −2 এর চেয়ে কম হয় ।

(1/5) * 2 −2 <1/5 সুতরাং উত্তরটি সর্বদা একটি সঠিক বিভাগ করা এবং শূন্যের দিকে গোল করার সমান হবে।


দুর্ভাগ্যক্রমে এটি সমস্ত বিভাজনকারীদের পক্ষে কাজ করে না।

যদি আমরা শূন্য থেকে দূরে 0.64 নির্দিষ্ট পয়েন্ট নম্বর হিসাবে 4/7 উপস্থাপন করার চেষ্টা করি আমরা (6/7) * 2 -64 এর ত্রুটি দিয়ে শেষ করি । কেবলমাত্র 2 64 এর নীচে i মান দিয়ে গুণনের পরে আমরা কেবল 6/7 এর নীচে একটি ত্রুটি দিয়ে শেষ করি এবং চারটি দিয়ে ভাগ করার পরে আমরা 1.5 / 7 এর নীচে একটি ত্রুটি নিয়ে শেষ করি যা 1/7 এর চেয়ে বেশি greater

সুতরাং 7 দ্বারা বিভাজন কার্যকরভাবে প্রয়োগ করতে আমাদের 0.65 নির্দিষ্ট পয়েন্ট সংখ্যা দিয়ে গুণ করতে হবে। আমরা আমাদের নির্ধারিত পয়েন্ট সংখ্যার নিম্ন 64 বিট দিয়ে গুণ করে তারপরে বাস্তবায়ন করতে পারি, তারপরে মূল সংখ্যাটি যুক্ত করুন (এটি ক্যারি বিটের মধ্যে উপচে পড়তে পারে) তারপরে ক্যারি দিয়ে ঘোরান।


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

2
কোডটিতে মডুলার পাটিগণিতের সাথে কিছুই করার কিছুই দেখছি না। ডুনো যেখানে আরও কিছু কমেন্টার তা পেয়ে আসছে।
প্লাগওয়াশ

3
এটি কোনও রেজিস্টারে সমস্ত পূর্ণসংখ্যার গণকের মতো মডুলো 2। N। en.wikedia.org/wiki/…
পিটার

4
@ পিটারকর্ডস মডিউলার গুণক বিপরীতগুলি সঠিক বিভাগের জন্য ব্যবহৃত হয়, আফাক তারা সাধারণ বিভাগের জন্য দরকারী না
হ্যারোল্ড

4
@ পিটারকর্ডস স্থির-পয়েন্ট পারস্পরিক ক্রিয়াকলাপ দ্বারা গুণ? সবাই এটাকে কী বলে আমি জানি না তবে আমি সম্ভবত এটিকে কল করেছি, এটি মোটামুটি বর্ণনামূলক
হ্যারোড

12

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

http://gmplib.org/~tege/divcnst-pldi94.pdf

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

Figure.২ চিত্রে নীচে স্ক্রোল করুন, যা সংজ্ঞা দেয় যে কীভাবে একটি উচ্চারণ গুণক (সর্বোচ্চ আকার এন + 1 বিট) উত্পন্ন হয়, তবে প্রক্রিয়াটি স্পষ্টভাবে ব্যাখ্যা করে না। আমি এটি নীচে ব্যাখ্যা করব।

চিত্র ৪.২ এবং চিত্র show.২ দেখায় যে কীভাবে বেশিরভাগ বিভাজনকারীদের জন্য গুণককে একটি এন বিট বা কম গুণক হিসাবে কমাতে পারে। সমীকরণ 4.5 ব্যাখ্যা করে যে কীভাবে সূত্রটি 4.1 এবং 4.2 চিত্রের এন + 1 বিট গুণকগুলির সাথে ডিল করতে ব্যবহৃত হয়েছিল।

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

চিত্র 6.2 এ ফিরে যাওয়া। হালকা এবং mhigh এর জন্য অঙ্ক (লভ্যাংশ) কেবলমাত্র একটি বাদ্য (ডিভাইডার)> 2 ^ (এন -1) (যখন ℓ == এন => মলো = 2 ^ (2 এন)) এর ক্ষেত্রে বড় হতে পারে এন / ডি এর জন্য অনুকূলিত প্রতিস্থাপন একটি তুলনা (যদি এন> = ডি, কিউ = 1, অন্য কিউ = 0) হয়, সুতরাং কোনও গুণক তৈরি হয় না। Mlow এবং mhigh এর প্রাথমিক মানগুলি N + 1 বিট হবে এবং প্রতিটি এন + 1 বিট মান (mlow বা mhigh) উত্পাদন করতে দুটি udword / uword বিভাজক ব্যবহার করা যেতে পারে। উদাহরণ হিসাবে 64 বিট মোডে এক্স 86 ব্যবহার করুন:

; upper 8 bytes of dividend = 2^(ℓ) = (upper part of 2^(N+ℓ))
; lower 8 bytes of dividend for mlow  = 0
; lower 8 bytes of dividend for mhigh = 2^(N+ℓ-prec) = 2^(ℓ+shpre) = 2^(ℓ+e)
dividend  dq    2 dup(?)        ;16 byte dividend
divisor   dq    1 dup(?)        ; 8 byte divisor

; ...
        mov     rcx,divisor
        mov     rdx,0
        mov     rax,dividend+8     ;upper 8 bytes of dividend
        div     rcx                ;after div, rax == 1
        mov     rax,dividend       ;lower 8 bytes of dividend
        div     rcx
        mov     rdx,1              ;rdx:rax = N+1 bit value = 65 bit value

আপনি এটি জিসিসির সাথে পরীক্ষা করতে পারেন। কীভাবে j = i / 5 পরিচালনা করা হয় তা আপনি ইতিমধ্যে দেখেছেন। কীভাবে j = i / 7 পরিচালনা করা হয় তা দেখুন (যা এন + 1 বিট গুণক ক্ষেত্রে হওয়া উচিত)।

বেশিরভাগ বর্তমান প্রসেসরের উপর, গুণকের একটি নির্দিষ্ট সময় থাকে, তাই প্রাক-শিফ্টের প্রয়োজন হয় না। এক্স ৮ For-এর জন্য, শেষ ফলাফলটি বেশিরভাগ বিভাজনকারীদের জন্য একটি দুটি নির্দেশ ক্রম, এবং 7 টির মত বিভাজনকারীদের জন্য পাঁচটি নির্দেশের ক্রম (পিডিএফ ফাইলের 4.5 এবং চিত্র 4.2 সমীকরণে এন + 1 বিট গুণক অনুকরণ করার জন্য)। এক্স 86-64 কোড উদাহরণ:

;       rax = dividend, rbx = 64 bit (or less) multiplier, rcx = post shift count
;       two instruction sequence for most divisors:

        mul     rbx                     ;rdx = upper 64 bits of product
        shr     rdx,cl                  ;rdx = quotient
;
;       five instruction sequence for divisors like 7
;       to emulate 65 bit multiplier (rbx = lower 64 bits of multiplier)

        mul     rbx                     ;rdx = upper 64 bits of product
        sub     rbx,rdx                 ;rbx -= rdx
        shr     rbx,1                   ;rbx >>= 1
        add     rdx,rbx                 ;rdx = upper 64 bits of corrected product
        shr     rdx,cl                  ;rdx = quotient
;       ...

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

১৯৯৪ তারিখের এই কাগজটি একে সিসিতে প্রয়োগ করার বর্ণনা দেয়, তাই সময় এসেছে জিসিসি-এর অ্যালগোরিদম আপডেট করার জন্য। এই URL টির 94 টি কী বোঝায় তা দেখার জন্য অন্যের কাছে সময় নেই।
এড গ্রিম

0

আমি কিছুটা ভিন্ন কোণ থেকে উত্তর দেব: কারণ এটি করার অনুমতি দেওয়া হয়েছে।

সি এবং সি ++ একটি বিমূর্ত মেশিনের বিপরীতে সংজ্ঞায়িত করা হয়। কম্পাইলার নিম্নলিখিত কংক্রিট মেশিনে বিমূর্ত মেশিন পরিপ্রেক্ষিতে এই প্রোগ্রাম রূপান্তরিত যেমন-যদি নিয়ম।

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