কোনও ফাংশনের ইনলাইন সংস্করণ অন-ইনলাইন সংস্করণের চেয়ে আলাদা মান প্রদান করে


85

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

#include <cmath>
#include <iostream>

bool is_cube(double r)
{
    return floor(cbrt(r)) == cbrt(r);
}

bool inline is_cube_inline(double r)
{
    return floor(cbrt(r)) == cbrt(r);
}

int main()
{
    std::cout << (floor(cbrt(27.0)) == cbrt(27.0)) << std::endl;
    std::cout << (is_cube(27.0)) << std::endl;
    std::cout << (is_cube_inline(27.0)) << std::endl;
}

আমি আশা করব যে সমস্ত ফলাফল আউটপুট সমান হবে 1তবে এটি আসলে (আউটজুটগুলি (জি ++ 8.3.1, কোনও পতাকা নেই)):

1
0
1

পরিবর্তে

1
1
1

সম্পাদনা করুন: ঝাঁকুনি ++ 7.0.0 এটিকে আউটপুট দেয়:

0
0
0

এবং জি ++ -এছাড়া:

1
1
1

4
আপনি কি সংকলক, সংকলক বিকল্পগুলি ব্যবহার করছেন এবং কোন মেশিনটি সরবরাহ করতে পারেন? উইন্ডোজে জিসিসি 7.1 এ আমার জন্য ঠিক আছে।
ডায়োডাকাস

31
==ভাসমান পয়েন্টের মানগুলি নিয়ে কি সবসময় কিছুটা অনির্দেশ্য নয় ?
500 -


4
আপনি কি -Ofastবিকল্পটি সেট করেছেন , যা এই জাতীয়করণের অনুমতি দেয়?
সেমিডিএলপি

4
সংকলক মান লাইব্রেরিটি যখন ফেরায় cbrt(27.0)তার মানটির জন্য 0x0000000000000840ফেরত দেয় 0x0100000000000840। ডাবলস কমা পরে 16 তম সংখ্যায় পৃথক। আমার সিস্টেম: archlinux4.20 x64 gcc8.2.1 glibc2.28 সাথে চেক এই । জিসিসি বা গ্লিবসি ঠিক থাকলে আশ্চর্য।
কামিলকুক

উত্তর:


73

ব্যাখ্যা

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

  • ভাবের জটিলতা
  • সংকলন সময় মূল্যায়ন করার চেষ্টা করার সময় সংকলকটি কাটফট হিসাবে সংক্ষিপ্তরটি ব্যবহার করে
  • বিশেষ ক্ষেত্রে ব্যবহৃত অন্যান্য হিউরিস্টিক্স (যেমন যখন ক্ল্যাং এলিডগুলি লুপ হয়)

যদি প্রথম প্রকাশের মতো স্পষ্টরূপে কোনও অভিব্যক্তি সরবরাহ করা হয় তবে এর কম জটিলতা রয়েছে এবং সংকলকটি সংকলনের সময় এটির মূল্যায়ন করতে পারে।

একইভাবে, যদি কোনও ফাংশনটিকে ইনলাইন চিহ্নিত করা হয়, সংকলক সংকলনের সময় এটির মূল্যায়নের সম্ভাবনা বেশি কারণ ইনলাইন ফাংশন প্রান্তিককরণ উত্থাপন করে যেখানে মূল্যায়ন ঘটতে পারে।

উচ্চতর অপ্টিমাইজেশনের স্তরগুলিও এই প্রান্তিক প্রান্তকে বাড়িয়ে দেয়, যেমন- যথাযথ উদাহরণ হিসাবে, যেখানে উচ্চতর নির্ভুলতা সংকলন-সময় মূল্যায়নের কারণে সমস্ত এক্সপ্রেশন জিসিসি-তে সত্য হিসাবে মূল্যায়ন করে।

সংযোজক এক্সপ্লোরার এ আমরা এই আচরণটি পর্যবেক্ষণ করতে পারি। যখন -O1 দিয়ে সংকলিত হয় তখন কেবল ইনলাইন চিহ্নিত ফাংশনটি সংকলন-সময়ে মূল্যায়ন করা হয়, তবে -O3 এ উভয় ফাংশন সংকলন-সময়ে মূল্যায়ন করা হয়।

এনবি: সংকলক-এক্সপ্লোরার উদাহরণগুলিতে, আমি printfপরিবর্তে আইস্ট্রিম ব্যবহার করি কারণ এটি মূল ফাংশনের জটিলতা হ্রাস করে, প্রভাবটিকে আরও দৃশ্যমান করে তোলে।

যে inlineরানটাইম মূল্যায়ন প্রভাবিত করে না তা প্রদর্শন করে

আমরা নিশ্চিত করতে পারি যে স্ট্যান্ডার্ড ইনপুট থেকে মান অর্জন করে সংকলন সময়ে কোনওটিই এক্সপ্রেশনকে মূল্যায়ন করা হয় না এবং যখন আমরা এটি করি, সমস্ত 3 টি এক্সপ্রেশন এখানে প্রদর্শিত হিসাবে মিথ্যা প্রত্যাবর্তন করবে: https://ideone.com/QZbv6X

#include <cmath>
#include <iostream>

bool is_cube(double r)
{
    return floor(cbrt(r)) == cbrt(r);
}
 
bool inline is_cube_inline(double r)
{
    return floor(cbrt(r)) == cbrt(r);
}

int main()
{
    double value;
    std::cin >> value;
    std::cout << (floor(cbrt(value)) == cbrt(value)) << std::endl; // false
    std::cout << (is_cube(value)) << std::endl; // false
    std::cout << (is_cube_inline(value)) << std::endl; // false
}

এই উদাহরণটির সাথে বৈসাদৃশ্য করুন যেখানে আমরা একই সংকলক সেটিংস ব্যবহার করি তবে সংকলন সময়ে মান সরবরাহ করি যার ফলে উচ্চতর নির্ভুলতা সংকলন-সময় মূল্যায়ন হয়।


22

যেমন পর্যবেক্ষণ করা হয়েছে, ==ফ্লোটিং পয়েন্টের মানগুলির তুলনা করতে অপারেটরটি ব্যবহারের ফলে বিভিন্ন সংকলক এবং বিভিন্ন অপ্টিমাইজেশন স্তরে বিভিন্ন আউটপুট তৈরি হয়েছে।

ভাসমান পয়েন্টের মানগুলির তুলনা করার একটি ভাল উপায় হ'ল নিবন্ধে বর্ণিত আপেক্ষিক সহনশীলতা পরীক্ষা: ভাসমান-বিন্দু সহনশীলতা পুনর্বিবেচিত

আমরা প্রথমে Epsilon( আপেক্ষিক সহনশীলতা ) মান গণনা করি যা এই ক্ষেত্রে হবে:

double Epsilon = std::max(std::cbrt(r), std::floor(std::cbrt(r))) * std::numeric_limits<double>::epsilon();

এবং তারপরে এটিকে এই পদ্ধতিতে ইনলাইন এবং অন-ইনলাইন উভয় কাজে ব্যবহার করুন:

return (std::fabs(std::floor(std::cbrt(r)) - std::cbrt(r)) < Epsilon);

ফাংশনগুলি এখন:

bool is_cube(double r)
{
    double Epsilon = std::max(std::cbrt(r), std::floor(std::cbrt(r))) * std::numeric_limits<double>::epsilon();    
    return (std::fabs(std::floor(std::cbrt(r)) - std::cbrt(r)) < Epsilon);
}

bool inline is_cube_inline(double r)
{
    double Epsilon = std::max(std::cbrt(r), std::floor(std::cbrt(r))) * std::numeric_limits<double>::epsilon();
    return (std::fabs(std::round(std::cbrt(r)) - std::cbrt(r)) < Epsilon);
}

এখন আউটপুটটি [1 1 1]বিভিন্ন সংকলক এবং বিভিন্ন অপ্টিমাইজেশনের স্তরে প্রত্যাশা অনুযায়ী ( ) হবে ।

জীবন্ত উদাহরণ


max()আহ্বানের উদ্দেশ্য কী ? সংজ্ঞা অনুসারে, এর floor(x)চেয়ে কম বা সমান x, তাই max(x, floor(x))সর্বদা সমান হবে x
কেন থমাসেস

@KenThomases: এই বিশেষ ক্ষেত্রে, যেখানে এক যুক্তি maxঠিক হয় floorঅন্যান্য, এটা প্রয়োজন হয় না। তবে আমি একটি সাধারণ ক্ষেত্রে বিবেচনা করেছি যেখানে আর্গুমেন্টগুলি maxএকে অপরের থেকে স্বতন্ত্র যে মান বা ভাব হতে পারে।
পিডব্লিউ

operator==(double, double)ঠিক এটি করা উচিত নয় , একটি ছোট আকারের অ্যাপসিলনের চেয়ে পার্থক্যটি ছোট কিনা তা পরীক্ষা করে দেখুন? এসও সম্পর্কিত প্রায় 90% ভাসমান পয়েন্ট সম্পর্কিত প্রশ্নগুলির অস্তিত্ব থাকবে না।
পিটার - মনিকা

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