(A * b! = 0) জাভাতে (a! = 0 && b! = 0) এর চেয়ে দ্রুত কেন?


412

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

আমি এটি দিয়ে মূল্যায়ন করতে পারি

if (a != 0 && b != 0) { /* Some code */ }

বা বিকল্পভাবে

if (a*b != 0) { /* Some code */ }

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

long time;
final int len = 50000000;
int arbitrary = 0;
int[][] nums = new int[2][len];

for (double fraction = 0 ; fraction <= 0.9 ; fraction += 0.0078125) {
    for(int i = 0 ; i < 2 ; i++) {
        for(int j = 0 ; j < len ; j++) {
            double random = Math.random();

            if(random < fraction) nums[i][j] = 0;
            else nums[i][j] = (int) (random*15 + 1);
        }
    }

    time = System.currentTimeMillis();

    for(int i = 0 ; i < len ; i++) {
        if( /*insert nums[0][i]*nums[1][i]!=0 or nums[0][i]!=0 && nums[1][i]!=0*/ ) arbitrary++;
    }
    System.out.println(System.currentTimeMillis() - time);
}

এবং ফলাফলগুলি দেখায় যে আপনি যদি "ক" বা "বি" সময়ের ~ 3% এর চেয়ে 0 এর সমান হতে আশা করেন তবে তার চেয়ে a*b != 0দ্রুততর a!=0 && b!=0:

অ্যান্ড শূন্য অ-শূন্য ফলাফলের গ্রাফিকাল গ্রাফ

আমি কেন জানতে আগ্রহী। কেউ কি কিছু আলোকপাত করতে পারে? এটি কি সংকলক বা এটি হার্ডওয়্যার স্তরে?

সম্পাদনা: কৌতূহলের বাইরে ... এখন যখন আমি শাখার পূর্বাভাস সম্পর্কে জানতে পেরেছিলাম, তখন আমি ভাবছিলাম যে অ্যানালগ তুলনাটি একটি ওআর বি-এর জন্য কী প্রদর্শিত হবে:

অ বা শূন্য অ-শূন্যের গ্রাফ

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

হালনাগাদ

1- আমি !(a==0 || b==0)বিশ্লেষণে যুক্ত করে দেখি কী ঘটে।

2- আমি এছাড়াও অন্তর্ভুক্ত করা a != 0 || b != 0, (a+b) != 0এবং (a|b) != 0আউট কৌতুহল, শাখা ভবিষ্যদ্বাণী সম্পর্কে জানতে হয়। তবে এগুলি যুক্তিগতভাবে অন্যান্য অভিব্যক্তির সমতুল্য নয়, কারণ সত্যটিতে প্রত্যাবর্তনের জন্য কেবল একটি ওআর বি শূন্য হওয়া দরকার, তাই প্রক্রিয়াজাতকরণের দক্ষতার জন্য সেগুলি তুলনা করে বোঝানো হয় না।

3- আমি বিশ্লেষণের জন্য যে সত্যিকারের মানদণ্ডটি ব্যবহার করেছি তা যুক্ত করেছিলাম, যা কেবল একটি স্বেচ্ছাসেবীর ইনট ভেরিয়েবলটি পুনরাবৃত্তি করে।

4- কিছু লোক এর a != 0 & b != 0বিপরীতে অন্তর্ভুক্ত করার পরামর্শ দিচ্ছিল a != 0 && b != 0, ভবিষ্যদ্বাণী সহ যে এটি আরও ঘনিষ্ঠভাবে আচরণ করবে a*b != 0কারণ আমরা শাখার পূর্বাভাসের প্রভাবটি সরিয়ে দেব। আমি জানি না যে এটি &বুলিয়ান ভেরিয়েবলগুলির সাথে ব্যবহার করা যেতে পারে, আমি ভেবেছিলাম এটি কেবলমাত্র পূর্ণসংখ্যার সাথে বাইনারি অপারেশনের জন্য ব্যবহৃত হয়েছিল।

দ্রষ্টব্য: আমি যে সমস্ত প্রসঙ্গে বিবেচনা করছিলাম, প্রচ্ছন্ন ওভারফ্লো কোনও সমস্যা নয়, তবে সাধারণ প্রসঙ্গে এটি অবশ্যই একটি গুরুত্বপূর্ণ বিবেচনা।

সিপিইউ: ইনটেল কোর i7-3610QM @ 2.3GHz

জাভা সংস্করণ: 1.8.0_45
জাভা (টিএম) এসই রানটাইম এনভায়রনমেন্ট (বিল্ড 1.8.0_45-বি 14)
জাভা হটস্পট (টিএম) 64-বিট সার্ভার ভিএম (বিল্ড 25.45-বি02, মিশ্র মোড)


11
কি হবে if (!(a == 0 || b == 0))? মাইক্রোবেঞ্চমার্কগুলি কুখ্যাতভাবে বিশ্বাসযোগ্য নয়, এটি সত্যিই পরিমাপযোগ্য হওয়ার সম্ভাবনা নেই (to 3% আমার কাছে ত্রুটির প্রান্তিকের মতো শোনায়)।
এলিয়ট ফ্রিচ

9

16
পূর্বাভাসিত শাখাটি ভুল হলে ব্রাঞ্চিং ধীর হয় is a*b!=0এর একটি কম শাখা আছে
এরউইন বোলভিড

19
(1<<16) * (1<<16) == 0তবু উভয়ই শূন্য থেকে পৃথক।
কোডসইনচাউস

13
@ জিন: আপনার প্রস্তাবিত অপ্টিমাইজেশনটি বৈধ নয়। এমনকি ওভারফ্লো উপেক্ষা, a*bশূন্য যদি এক এর aএবং bশূন্য হয়; a|bউভয় হলেই শূন্য।
hmakholm

উত্তর:


240

আপনার বেঞ্চমার্কিংটি ত্রুটিযুক্ত হতে পারে এবং এই বিষয়টিকে মুখের মূল্যের ভিত্তিতে নিয়ে যাওয়া আমি এই বিষয়টি উপেক্ষা করছি ।

এটি কি সংকলক বা এটি হার্ডওয়্যার স্তরে?

এই পরে, আমি মনে করি:

  if (a != 0 && b != 0)

2 মেমরি লোড এবং দুটি শর্তসাপেক্ষ শাখা সংকলন করবে

  if (a * b != 0)

2 মেমরি লোড, একটি গুণ এবং একটি শর্তাধীন শাখা সংকলন করবে।

যদি হার্ডওয়ার-স্তরের শাখার পূর্বাভাস কার্যকর না হয় তবে দ্বিতীয় শর্তসাপেক্ষ শাখার চেয়ে বহুগুণ দ্রুত হওয়ার সম্ভাবনা রয়েছে। আপনি অনুপাত বাড়ানোর সাথে ... শাখার পূর্বাভাস কম কার্যকর হয়ে উঠছে।

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

(দ্রষ্টব্য: উপরের ব্যাখ্যাটি আরও বিস্তৃত


যাইহোক, এই অপটিমাইজেশনটি সম্পর্কে আপনার সতর্ক হওয়া উচিত। এমন কোনও মান আছে যেখানে a * b != 0ভুল উত্তর দেবে? পূর্ণসংখ্যার ওভারফ্লোতে প্রোডাক্টটির ফলাফল নির্ধারণের ক্ষেত্রে কেস বিবেচনা করুন।


হালনাগাদ

আপনার গ্রাফগুলি আমি যা বলেছিলাম তা নিশ্চিত করার প্রবণতা রয়েছে।

  • শর্তাধীন শাখার a * b != 0ক্ষেত্রে একটি "শাখার পূর্বাভাস" প্রভাবও রয়েছে এবং এটি গ্রাফগুলিতে প্রকাশিত হয়।

  • আপনি যদি এক্স-অক্ষের উপর 0.9 এর বাইরে কার্ভগুলি প্রজেক্ট করেন তবে মনে হয় এটি 1) তারা প্রায় 1.0 এবং 2 এ মিলিত হবে) মিটিং পয়েন্টটি প্রায় এক্স = 0.0 এর সমান ওয়াই মান হবে value


আপডেট 2

আমি বুঝতে পারি না কেন কার্ভগুলি কেস a + b != 0এবং কেসগুলির জন্য আলাদা a | b != 0। সেখানে হতে পারে কিছু শাখা ভবিষ্যতবক্তা যুক্তিবিজ্ঞান মধ্যে চালাক। বা এটি অন্য কিছু নির্দেশ করতে পারে।

(দ্রষ্টব্য যে এই ধরণের জিনিসটি একটি নির্দিষ্ট চিপ মডেল নম্বর বা এমনকি সংস্করণের জন্য নির্দিষ্ট হতে পারে your আপনার মানদণ্ডের ফলাফলগুলি অন্যান্য সিস্টেমে আলাদা হতে পারে on)

যাইহোক, তারা উভয়ের সমস্ত অ-নেতিবাচক মানের জন্য কাজ করার সুবিধা aএবং b


1
@ দেবোসমিতরে - ১) কোনও ডাব্লু'র উচিত হবে না। মধ্যবর্তী ফলাফলগুলি একটি রেজিস্টারে রাখা হবে। 2) দ্বিতীয় ক্ষেত্রে, দুটি উপলভ্য শাখা রয়েছে: একটি "কিছু কোড" কার্যকর করতে হবে এবং অন্যটি পরবর্তী বিবৃতিতে এড়িয়ে যাওয়ার পরে if
স্টিফেন সি

1
@StephenC আপনার সম্পর্কে একটি + খ এবং বিভ্রান্ত করা যাবে সঠিক | খ, কারণ রেখাচিত্র হয় একই, আমার মনে হয় এটা রং সত্যিই ঘনিষ্ঠ হচ্ছে। রঙিন অন্ধ মানুষের কাছে ক্ষমা!
মালজাম

3
@ njzk2 সম্ভাব্যতা দৃষ্টিকোণ থেকে সেই ক্ষেত্রে 50% (এর শূন্য সম্ভাবনা উপর অক্ষ অনুযায়ী প্রতিসম হওয়া উচিত a&bএবং a|b)। তারা, কিন্তু পুরোপুরি নয়, এটি ধাঁধা।
আন্তোনন লেজসেক

3
@ স্টেফেনসি কারণ a*b != 0এবং a+b != 0বেঞ্চমার্ক আলাদাভাবে কারণ কারণ a+b != 0মোটেই সমান নয় এবং কখনও বেঞ্চমার্ক করা উচিত হয়নি। উদাহরণস্বরূপ, এর সাথে a = 1, b = 0প্রথম প্রকাশটি মিথ্যাতে মূল্যায়ন করে তবে দ্বিতীয়টি সত্যকে মূল্যায়ন করে। সংখ্যাবৃদ্ধি সাজানোর একটি মত কাজ করে এবং , অপারেটর যেহেতু অ্যাড সাজানোর একটি মত কাজ করে বা অপারেটর।
জেএস 1

2
@ অ্যান্টোনলেজেক আমি মনে করি সম্ভাবনাগুলি আলাদা হবে। আপনার যদি nশূন্য থাকে তবে উভয়ের সম্ভাবনা aএবং bশূন্য হওয়ার সাথে সাথে বৃদ্ধি হয় n। কোনও ANDঅপারেশনে, nতাদের মধ্যে একজনের শূন্য-শঙ্কিত হওয়ার সম্ভাবনা বেশি হওয়ার সাথে সাথে শর্তটি পূরণ করা হয়। এটি একটি জন্য বিপরীত ORঅপারেশন (তাদের হয় এক সম্ভাবনা শূন্য হচ্ছে সঙ্গে বাড়ে n)। এটি গাণিতিক দৃষ্টিভঙ্গির উপর ভিত্তি করে। হার্ডওয়্যারটি কীভাবে এটি কাজ করে তা আমি নিশ্চিত নই।
WYSIWYG

70

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

  • (a|b)!=0এবং (a+b)!=0যদি উভয় মান শূন্য হয় তবে পরীক্ষা করুন a != 0 && b != 0এবং উভয়ই শূন্য নয় (a*b)!=0কিনা তা পরীক্ষা করুন । সুতরাং আপনি কেবল গণিতের সময়কে তুলনা করছেন না: যদি শর্তটি প্রায়শই সত্য হয় তবে এটি শরীরের আরও মৃত্যুদন্ড কার্যকর করে, এতে আরও বেশি সময় লাগে।if

  • (a+b)!=0 ধনাত্মক এবং নেতিবাচক মানগুলির জন্য শূন্যের সমষ্টিগুলির জন্য ভুল কাজ করবে, সুতরাং আপনি এটি এখানে কাজ করে এমনকি সাধারণ ক্ষেত্রে এটি ব্যবহার করতে পারবেন না।

  • একইভাবে, (a*b)!=0ওভারফ্লো হওয়া মানগুলির জন্য ভুল কাজ করবে। (এলোমেলো উদাহরণ: 196608 * 327680 0 কারণ সত্য ফলাফলটি 2 32 দ্বারা বিভাজ্য হতে চলেছে , সুতরাং এর কম 32 বিট 0 হয়, এবং যদি এটি intঅপারেশন হয় তবে আপনার বিটগুলি সমস্তই পাওয়া যায় ))

  • বহিরাগত ( fraction) লুপের প্রথম কয়েকটি রান চলাকালীন ভিএম অভিব্যক্তিটি অনুকূল করে তোলে, যখন fraction0 হয়, যখন শাখাগুলি প্রায় নেওয়া হয় না। আপনি fraction0.5 থেকে শুরু করলে অপ্টিমাইজার বিভিন্ন কাজ করতে পারে ।

  • ভিএম যদি এখানে কিছু অ্যারে বাউন্ড চেক মুছে ফেলতে সক্ষম না করে, সীমাবদ্ধ চেকের কারণে অভিব্যক্তিটিতে আরও চারটি শাখা রয়েছে এবং নিম্ন স্তরে কী ঘটছে তা নির্ধারণের চেষ্টা করার সময় এটি একটি জটিল কারণ। আপনি বিভিন্ন ফলাফল পেতে পারে আপনি দুই ফ্ল্যাট অ্যারে মধ্যে দ্বি-মাত্রিক অ্যারে বিভক্ত পরিবর্তন nums[0][i]এবং nums[1][i]করতে nums0[i]এবং nums1[i]

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

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

  • System.currentTimeMillis()বেশিরভাগ সিস্টেমে +/- 10 এমএসের চেয়ে বেশি সঠিক নয়। System.nanoTime()সাধারণত আরও সঠিক।

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

আপনি যদি ভিএম দ্বারা উত্পাদিত মেশিন কোডটি বিচ্ছিন্ন করতে পারেন তবে এটি কী করে তা অনুমান করার চেষ্টা করার চেয়ে এটি করুন!


24

এখানে উত্তরগুলি ভাল, যদিও আমার একটি ধারণা ছিল যা জিনিসগুলির উন্নতি করতে পারে।

যেহেতু দুটি শাখা এবং সম্পর্কিত শাখার পূর্বাভাস সম্ভবত অপরাধী, তাই আমরা যুক্তিটি কোনও পরিবর্তন না করেই শাখা প্রশাখাকে একটি শাখায় হ্রাস করতে সক্ষম হতে পারি।

bool aNotZero = (nums[0][i] != 0);
bool bNotZero = (nums[1][i] != 0);
if (aNotZero && bNotZero) { /* Some code */ }

এটি কাজ করতে পারে

int a = nums[0][i];
int b = nums[1][i];
if (a != 0 && b != 0) { /* Some code */ }

কারণ হ'ল শর্ট সার্কিটের বিধি দ্বারা, যদি প্রথম বুলিয়ান মিথ্যা হয়, তবে দ্বিতীয়টির মূল্যায়ন করা উচিত নয়। ভুয়া nums[1][i]থাকলে মূল্যায়ন এড়াতে এটি অতিরিক্ত শাখা সঞ্চালন করতে হবে nums[0][i]। এখন, আপনি nums[1][i]মূল্যায়ন করবেন না সেটিকে যত্নশীল নাও করতে পারেন , তবে সংকলকটি নিশ্চিত হতে পারে না যে আপনি যখন করবেন তখন এটি পরিসীমা ছাড়বে না বা নাল রেফারেন্স করবে না। ইফ ব্লকটিকে সরল বলগুলিতে হ্রাস করে, সংকলকটি বুঝতে যথেষ্ট স্মার্ট হতে পারে যে দ্বিতীয় বুলিয়ান অকারণে মূল্যায়ন করলে নেতিবাচক পার্শ্ব প্রতিক্রিয়া হবে না have


3
উত্সাহিত যদিও আমার একটি অনুভূতি রয়েছে এটি প্রশ্নের পুরোপুরি উত্তর দেয় না ।
পিয়েরে আরলাড

3
শাখাবিহীন শাখা থেকে যুক্তি পরিবর্তন না করে কোনও শাখা প্রবর্তন করার এক উপায় (যদি আপনি যেভাবে প্রতিক্রিয়া পেয়েছিলেন aএবং bপার্শ্ব প্রতিক্রিয়া দেখিয়েছিলেন তবে আপনি তা রাখতেন)। আপনার এখনও আছে &&তাই আপনার এখনও একটি শাখা আছে।
জন হান্না

11

যখন আমরা গুণ করি, একটি সংখ্যা 0 হলেও, পণ্যটি 0 হয় writing লেখার সময়

    (a*b != 0)

এটি 0 দ্বারা শুরু হওয়া পুনরাবৃত্তির প্রথম কয়েকটি ঘটনাকে মুছে ফেলার ফলে ফলাফলটির মূল্যায়ন করে ফলাফল হিসাবে যখন শর্তটি হয় তখন তুলনাগুলি তার চেয়ে কম হয়

   (a != 0 && b != 0)

যেখানে প্রতিটি উপাদান 0 এর সাথে তুলনা করা হয় এবং মূল্যায়ন করা হয়। অতএব প্রয়োজনীয় সময় কম হয়। তবে আমি বিশ্বাস করি যে দ্বিতীয় শর্তটি আপনাকে আরও সঠিক সমাধান দিতে পারে।


4
দ্বিতীয় প্রকাশে যদি aশূন্য হয় তবে bমূল্যায়ন করা দরকার না কারণ পুরো প্রকাশটি ইতিমধ্যে মিথ্যা। সুতরাং প্রতিটি উপাদান তুলনা করা সত্য নয়।
কুবা ওয়াইরোস্টেক

9

আপনি এলোমেলোভাবে ইনপুট ডেটা ব্যবহার করছেন যা শাখাগুলি অনির্দেশ্য করে তোলে। অনুশীলনে শাখাগুলি প্রায়শই (~ 90%) অনুমানযোগ্য হয় তাই বাস্তব কোডটিতে শাখাফুল কোডটি দ্রুত হওয়ার সম্ভাবনা থাকে।

বলেছে। এর a*b != 0চেয়ে দ্রুত কীভাবে হতে পারে তা আমি দেখছি না (a|b) != 0। সাধারণত পূর্ণসংখ্যার গুণটি কিছুটা OR এর চেয়ে ব্যয়বহুল। তবে এর মতো জিনিস মাঝে মাঝে অদ্ভুত হয়ে যায়। প্রসেসর ক্যাশে ইফেক্টের গ্যালারী থেকে "উদাহরণ 7: হার্ডওয়্যার জটিলতা" উদাহরণ দেখুন ।


2
&"বিটওয়াইজ ওআর" নয় তবে ( |
এক্ষেত্রে

1
@ সিগি টিআইএল জাভা '&' আসলে একটি যৌক্তিক এবং সংক্ষিপ্ত-সার্কিট ছাড়াই।
স্ট্যাকড ক্রোকড
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.