একজন কনস্ট্রের এক্সপ্রেসকে কীভাবে এত তাড়াতাড়ি মূল্যায়ন করা যায়


13

আমি দৃ const় মত প্রকাশের চেষ্টা করছি যা সংকলন সময়ে মূল্যায়ন করা হয়। তবে আমি এমন একটি উদাহরণ দিয়ে খেলেছি যা সংকলনের সময় কার্যকর করার সময় অবিশ্বাস্যরকম দ্রুত বলে মনে হয়।

#include<iostream> 

constexpr long int fib(int n) { 
    return (n <= 1)? n : fib(n-1) + fib(n-2); 
} 

int main () {  
    long int res = fib(45); 
    std::cout << res; 
    return 0; 
} 

আমি এই কোডটি চালানোর সময় এটি চালাতে প্রায় 7 সেকেন্ড সময় লাগে। এ পর্যন্ত সব ঠিকই. কিন্তু আমি যখন পরিবর্তন long int res = fib(45)করার জন্য const long int res = fib(45)এটা এমনকি একটি দ্বিতীয় না লাগে। আমার বোঝার জন্য এটি সংকলন সময়ে মূল্যায়ন করা হয়। তবে সংকলনটি প্রায় ০.০ সেকেন্ড সময় নেয়

সংকলকটি কীভাবে এটি এত তাড়াতাড়ি মূল্যায়ন করতে পারে তবে রানটাইমে এটি এত বেশি সময় নেয়? আমি জিসিসি 5.4.0 ব্যবহার করছি।


7
আমি অনুমান করি যে সংকলকটি ফাংশনটিতে কল করে তা ক্যাশে করে fib। আপনার উপরের ফিবোনাচি সংখ্যাগুলি বাস্তবায়ন হ'ল পিরিয়টি ধীর। রানটাইম কোডে ফাংশনের মানগুলি ক্যাশে করার চেষ্টা করুন এবং এটি আরও দ্রুত হবে।
n314159

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

1
@ অ্যালানবার্টলস হ্যাঁ আমি এটি -O3 দিয়ে সংকলন করেছি।
পিটার 234

1
আমি ধরে নিলাম যে সংকলক ক্যাশে ফাংশনটি কল করে ফাংশনটি 2 ^ 45 বারের পরিবর্তে কেবল 46 বার (প্রতিটি সম্ভাব্য যুক্তির জন্য একবার 0-45) বর্ধিত করা উচিত। তবে আমি জানি না জিসিসি এর মতো কাজ করে কিনা।
চুরিল

3
পছন্দ করুন যখন মূল্যায়ন রানটাইমে এত সময় নেয় তখন সংকলনটি কীভাবে এত দ্রুত হতে পারে?
পিটার 234

উত্তর:


5

সংকলকটি ছোট মানগুলিকে ক্যাশে করে এবং রানটাইম সংস্করণে যেমনটি করা হয় তেমন পুনঃসংযোগের প্রয়োজন হয় না।
(অপটিমাইজারটি খুব ভাল এবং আমার কাছে বোধগম্য এমন বিশেষ মামলাগুলির সাথে কৌতুক সহ প্রচুর কোড জেনারেট করে; নিষ্পাপ 2 rec 45 পুনরাবৃত্তিতে কয়েক ঘন্টা সময় লাগতে পারে))

আপনি যদি পূর্বের মানগুলি সংরক্ষণ করেন:

int cache[100] = {1, 1};

long int fib(int n) {
    int res = cache[n];
    return res ? res : (cache[n] = fib(n-1) + fib(n-2));
} 

রানটাইম সংস্করণটি কম্পাইলারের চেয়ে অনেক দ্রুত।


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

... এটি ক্যাচিংয়ের পরিবর্তে সংকলকটি ফাইব (এন -২) এবং ফাইব (এন -১) এর মধ্যে কিছু সম্পর্ক প্রমাণ করতে সক্ষম এবং ফাইবকে কল করার পরিবর্তে (এন -২) এটি ফাইবকে ব্যবহার করে (এন -২) ) যে গণনা মান। আমি মনে করি যে 5.4 এর আউটপুটে আমি যা দেখছি তার সাথে মিলে যায় যা কনস্টেক্সপ অপসারণ করে এবং -O2 ব্যবহার করে।
সুমা

1
আপনার কি এমন কোনও লিঙ্ক বা অন্যান্য উত্স আছে যা ব্যাখ্যা করে যে সংকলন সময়ে কী কী অপ্টিমাইজেশন করা যেতে পারে?
পিটার 234

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

@ সুমা কেবল একবার পুনরাবৃত্তি করতে সমস্যা নেই। যেহেতু একটি পুনরাবৃত্ত সংস্করণ রয়েছে তাই অবশ্যই একটি পুনরাবৃত্ত সংস্করণ রয়েছে যা উদাহরণস্বরূপ লেজ পুনরাবৃত্তি হিসাবে ব্যবহার করে।
Ctx

1

আপনি 5.4 এর সাথে আকর্ষণীয় খুঁজে পেতে পারেন যা ফাংশনটি সম্পূর্ণরূপে নির্মূল হয় না, এর জন্য আপনার কমপক্ষে 6.1 প্রয়োজন .1

আমি মনে করি না এখানে কোনও ক্যাশে হচ্ছে। আমি নিশ্চিত যে অপটিমাইজার যথেষ্ট স্মার্ট fib(n - 2)এবং এর মধ্যে সম্পর্ক প্রমাণ করার জন্য fib(n-1)এবং দ্বিতীয় কলটি সম্পূর্ণভাবে এড়িয়ে চলে। এটি জিসিসি 5.4 আউটপুট (গডবোল্ট থেকে প্রাপ্ত) কোনও constexprএবং -O2 সহ:

fib(long):
        cmp     rdi, 1
        push    r12
        mov     r12, rdi
        push    rbp
        push    rbx
        jle     .L4
        mov     rbx, rdi
        xor     ebp, ebp
.L3:
        lea     rdi, [rbx-1]
        sub     rbx, 2
        call    fib(long)
        add     rbp, rax
        cmp     rbx, 1
        jg      .L3
        and     r12d, 1
.L2:
        lea     rax, [r12+rbp]
        pop     rbx
        pop     rbp
        pop     r12
        ret
.L4:
        xor     ebp, ebp
        jmp     .L2

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


আমার মনে হয় আমি ভুল .L3 এ একটি লুপ রয়েছে এবং ফাইবটি সমস্ত নীচের তন্তুগুলির উপরে লুপ করছে। -O2 দিয়ে এটি এখনও ক্ষতিকারক।
সুমা
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.