আমি আমার কম্পিউটারে একটি কৌতূহলী জিনিস লক্ষ্য করেছি। * হাতে লিখিত বিভাজ্যতা পরীক্ষা %
অপারেটরের তুলনায় উল্লেখযোগ্যভাবে দ্রুত is সর্বনিম্ন উদাহরণ বিবেচনা করুন:
* এএমডি রাইজেন থ্রেড্রিপার 2990WX, জিসিসি 9.2.0
static int divisible_ui_p(unsigned int m, unsigned int a)
{
if (m <= a) {
if (m == a) {
return 1;
}
return 0;
}
m += a;
m >>= __builtin_ctz(m);
return divisible_ui_p(m, a);
}
উদাহরণটি বিজোড় a
এবং দ্বারা সীমাবদ্ধ m > 0
। তবে এটি সহজেই সকলের কাছে সাধারণীকরণ করা যায় a
এবং m
। কোডটি কেবল বিভাগটিকে সংযোজনগুলির একটি সিরিজে রূপান্তর করে।
এখন পরীক্ষা প্রোগ্রামটি সংকলিত বিবেচনা করুন -std=c99 -march=native -O3
:
for (unsigned int a = 1; a < 100000; a += 2) {
for (unsigned int m = 1; m < 100000; m += 1) {
#if 1
volatile int r = divisible_ui_p(m, a);
#else
volatile int r = (m % a == 0);
#endif
}
}
... এবং আমার কম্পিউটারে ফলাফল:
| implementation | time [secs] |
|--------------------|-------------|
| divisible_ui_p | 8.52user |
| builtin % operator | 17.61user |
অতএব 2 গুণ বেশি দ্রুত।
প্রশ্ন: কোডটি আপনার মেশিনে কীভাবে আচরণ করে তা আমাকে বলতে পারেন? এটি কী জিসিসিতে অপ্টিমাইজেশনের সুযোগ মিস করেছে? আপনি আরও দ্রুত এই পরীক্ষা করতে পারেন?
আপডেট: অনুরোধ হিসাবে, এখানে একটি সংক্ষিপ্ত পুনরুত্পাদনযোগ্য উদাহরণ:
#include <assert.h>
static int divisible_ui_p(unsigned int m, unsigned int a)
{
if (m <= a) {
if (m == a) {
return 1;
}
return 0;
}
m += a;
m >>= __builtin_ctz(m);
return divisible_ui_p(m, a);
}
int main()
{
for (unsigned int a = 1; a < 100000; a += 2) {
for (unsigned int m = 1; m < 100000; m += 1) {
assert(divisible_ui_p(m, a) == (m % a == 0));
#if 1
volatile int r = divisible_ui_p(m, a);
#else
volatile int r = (m % a == 0);
#endif
}
}
return 0;
}
gcc -std=c99 -march=native -O3 -DNDEBUG
এএমডি রাইজেন থ্রেড্রিপার 2990WX এর সাথে সংকলিত
gcc --version
gcc (Gentoo 9.2.0-r2 p3) 9.2.0
আপডেট 2: অনুরোধ অনুসারে, যে সংস্করণটি যে কোনওটি পরিচালনা করতে পারে a
এবং m
(আপনি যদি পূর্ণসংখ্যার ওভারফ্লো এড়াতে চান তবে ইনপুট পূর্ণসংখ্যার চেয়ে দ্বিগুণ দীর্ঘ সময় পূর্ণসংখ্যা টাইপের সাথে পরীক্ষাটি প্রয়োগ করতে হবে):
int divisible_ui_p(unsigned int m, unsigned int a)
{
#if 1
/* handles even a */
int alpha = __builtin_ctz(a);
if (alpha) {
if (__builtin_ctz(m) < alpha) {
return 0;
}
a >>= alpha;
}
#endif
while (m > a) {
m += a;
m >>= __builtin_ctz(m);
}
if (m == a) {
return 1;
}
#if 1
/* ensures that 0 is divisible by anything */
if (m == 0) {
return 1;
}
#endif
return 0;
}
r
গণনা করেছেন তা সত্যই একে অপরের সমান।
a % b
আছে b
তুলনায় অনেক ছোট a
। আপনার পরীক্ষার ক্ষেত্রে বেশিরভাগ পুনরাবৃত্তির মাধ্যমে এগুলি একই আকারের বা b
বড় আকারের হয় এবং আপনার সংস্করণগুলি সেই পরিস্থিতিতে অনেকগুলি সিপিইউতে দ্রুততর হতে পারে।