(A + B + C) ≠ (A + C + B) এবং সংকলক পুনঃক্রম


108

দুটি 32-বিট পূর্ণসংখ্যা যোগ করার ফলে পূর্ণসংখ্যার ওভারফ্লো হতে পারে:

uint64_t u64_z = u32_x + u32_y;

32-বিট পূর্ণসংখ্যার মধ্যে কোনও একটি আগে কাস্ট করা বা 64-বিট পূর্ণসংখ্যায় যুক্ত করা গেলে এই ওভারফ্লো এড়ানো যায়।

uint64_t u64_z = u32_x + u64_a + u32_y;

তবে, যদি সংকলক সংযোজনটিকে পুনরায় অর্ডার করার সিদ্ধান্ত নেয়:

uint64_t u64_z = u32_x + u32_y + u64_a;

পূর্ণসংখ্যা ওভারফ্লো এখনও ঘটতে পারে।

সংকলকগণ কি এ জাতীয় পুনঃক্রম করার অনুমতি দেয় বা আমরা ফলাফলের অসঙ্গতি লক্ষ্য করতে এবং অভিব্যক্তি আদেশটি যেমন রাখি তেমন তাদের বিশ্বাস করতে পারি?


15
আপনি আসলে পূর্ণসংখ্যার ওভারফ্লো দেখান না কারণ আপনি যুক্ত হওয়া uint32_tমান হিসাবে উপস্থিত হয় - যা উপচে পড়ে না, তারা মোড়কে দেয়। এগুলি ভিন্ন আচরণ নয়।
মার্টিন বোনার

5
সি ++ স্ট্যান্ডার্ডের ১.৯ বিভাগটি দেখুন, এটি সরাসরি আপনার প্রশ্নের উত্তর দেয় (এমন একটি উদাহরণও রয়েছে যা প্রায় আপনার মতো একই)।
হল্ট

3
@ টাল: অন্যরা যেমন ইতিমধ্যে জানিয়েছে: পূর্ণসংখ্যার কোনও ওভারফ্লো নেই। স্বাক্ষরবিহীনভাবে মোড়কে সংজ্ঞায়িত করা হয়, স্বাক্ষরিত হওয়ার জন্য এটি অনির্ধারিত আচরণ, সুতরাং অনুনাসিক ডেমোনস সহ যে কোনও বাস্তবায়ন তা করবে।
এই সাইটের জন্য খুব সৎ

5
@ টাল: বাজে! আমি ইতিমধ্যে লিখেছি: স্ট্যান্ডার্ডটি খুব স্পষ্ট এবং মোড়কের প্রয়োজন, স্যাচুরেটিং নয় (এটি স্বাক্ষরিত দ্বারা সম্ভব হবে, এটি স্ট্যান্ডার্ড হিসাবে ইউবি।
এই সাইটের পক্ষে খুব সত্য

15
@ রুস্টিক্স: আপনি এটিকে মোড়ক বা উপচে পড়া বলছেন না কেন , পয়েন্টটি এর ((uint32_t)-1 + (uint32_t)1) + (uint64_t)0ফলস্বরূপ রয়েছে 0, যেখানে (uint32_t)-1 + ((uint32_t)1 + (uint64_t)0)ফলাফল রয়েছে 0x100000000এবং এই দুটি মান সমান নয়। সুতরাং এটি উল্লেখযোগ্য যে সংকলক সেই রূপান্তরটি প্রয়োগ করতে পারে কি না। তবে হ্যাঁ, মানকটি স্বাক্ষরিত পূর্ণসংখ্যার জন্য কেবল "ওভারফ্লো" শব্দটি ব্যবহার করে, স্বাক্ষরবিহীন নয়।
স্টিভ জেসপ

উত্তর:


84

অপ্টিমাইজার যদি এই জাতীয় পুনঃক্রম করে তবে এটি সি স্পেসিফিকেশনের সাথে আবদ্ধ, সুতরাং এই জাতীয় পুনঃনির্মাণ হয়ে উঠবে:

uint64_t u64_z = (uint64_t)u32_x + (uint64_t)u32_y + u64_a;

নীতি:

আমরা দিয়ে শুরু

uint64_t u64_z = u32_x + u64_a + u32_y;

বাম থেকে ডানে সংযোজন সঞ্চালিত হয়।

পূর্ণসংখ্যার প্রচারের বিধিগুলিতে বলা হয়েছে যে আসল প্রকাশের প্রথম সংযোজনে u32_xপদোন্নতি দেওয়া হবে uint64_t। দ্বিতীয় সংযোজনটিতেও u32_yপদোন্নতি দেওয়া হবে uint64_t

সুতরাং, অর্ডার সি স্পেসিফিকেশনের সঙ্গে সঙ্গতিশীল হতে যে কোনো অপ্টিমাইজার প্রচার আবশ্যক u32_xএবং u32_y64 স্বাক্ষরবিহীন মান বিট। এটি একটি কাস্ট যোগ করার সমতুল্য। (আসল অনুকূলকরণটি সি স্তরে করা হয় না, তবে আমি সি সংকেত ব্যবহার করি কারণ এটি আমরা বুঝতে পারি এমন একটি স্বরলিপি))


এটি কি বাম-সাহসী নয়, তাই না (u32_x + u32_t) + u64_a?
25-18

12
@ ব্যবহারহীন: ক্লাস সব কিছু 64৪ বিট করে ফেলেছে। এখন অর্ডারটি মোটেই কোনও পার্থক্য করে না। সংকলকটির সাহচর্য অনুসরণ করার দরকার নেই, এটি ঠিক একই ফলাফলটি তৈরি করতে হবে যেমনটি এটি করেছে।
gnasher729

2
দেখে মনে হচ্ছে যে ওপির কোডটি সেইরূপ মূল্যায়ন করা হবে, যা সত্য নয়।
বেহুদা

@ ক্লাস - কেন এটি হচ্ছে তা ব্যাখ্যা করার যত্ন এবং আপনি আপনার কোডের নমুনায় ঠিক কীভাবে পৌঁছেছেন?
rustyx

1
@ রুস্টিক্স এর ব্যাখ্যা দরকার ছিল না। আমাকে একটি যুক্ত করতে চাপ দেওয়ার জন্য ধন্যবাদ।
ক্লাস লিন্ডব্যাক

28

একটি কম্পাইলার শুধুমাত্র অধীনে পুনরায়-অর্ডার অনুমোদিত হয় যেন নিয়ম। এটি হ'ল, যদি পুনঃক্রমটি সর্বদা নির্দিষ্ট অর্ডিংয়ের মতো একই ফলাফল দেয় তবে তা অনুমোদিত। অন্যথায় (যেমন আপনার উদাহরণ হিসাবে), না।

উদাহরণস্বরূপ, নিম্নলিখিত অভিব্যক্তি দেওয়া

i32big1 - i32big2 + i32small

বৃহত্তর তবে সমান হিসাবে পরিচিত দুটি মানকে বিয়োগ করার জন্য যা সাবধানে নির্মিত হয়েছে এবং কেবল তখনই অন্য ছোট মান যুক্ত করে (এইভাবে কোনও ওভারফ্লো এড়ানো), সংকলকটি পুনরায় অর্ডার করতে বেছে নিতে পারে:

(i32small - i32big2) + i32big1

এবং এই লক্ষ্যটির উপর নির্ভর করুন যে লক্ষ্য প্ল্যাটফর্ম সমস্যাগুলি প্রতিরোধের জন্য মোড়ক-বৃত্তাকার সহ দ্বি-পরিপূরক গাণিতিক ব্যবহার করছে। (সংকলকটি যদি রেজিস্টারগুলির জন্য চাপানো হয় এবং i32smallইতিমধ্যে একটি রেজিস্টারে রয়েছে তবে এ জাতীয় পুনঃনির্মাণ বুদ্ধিমান হতে পারে )।


ওপির উদাহরণ স্বাক্ষরযুক্ত প্রকারগুলি ব্যবহার করে। i32big1 - i32big2 + i32smallস্বাক্ষরিত প্রকারগুলি বোঝায়। অতিরিক্ত উদ্বেগগুলি কার্যকর হয়।
chux - মনিকা পুনরায় সেট করুন

@ chux একেবারে। আমি যে বিষয়টিটি তৈরির চেষ্টা করছিলাম সেটি হ'ল যদিও আমি লিখতে পারিনি (i32small-i32big2) + i32big1, (কারণ এটি ইউবির কারণ হতে পারে), সংকলকটি এটিকে কার্যকরভাবে পুনরায় সাজিয়ে তুলতে পারে কারণ সংকলকটি আচরণটি সঠিক হবে বলে আত্মবিশ্বাসী হতে পারে।
মার্টিন বোনার

3
@ চাক্স: ইউবির মতো অতিরিক্ত উদ্বেগগুলি কার্যকর হয় না, কারণ আমরা বিধি বিধি অনুসারে একটি সংকলক পুনরায় অর্ডারিংয়ের কথা বলছি। একটি নির্দিষ্ট সংকলক এর নিজস্ব ওভারফ্লো আচরণ জানার সুবিধা নিতে পারে।
এমসাল্টার

16

সি, সি ++, এবং উদ্দেশ্য-সি-তে "যেন" নিয়ম রয়েছে: সংযোজক যতক্ষণ না তার পছন্দমত যা কিছু করতে পারে ততক্ষণ যতক্ষণ না কোনও মানানসই প্রোগ্রাম পার্থক্য বলতে না পারে।

এই ভাষাগুলিতে, a + b + c (a + b) + c এর সমান হিসাবে সংজ্ঞায়িত করা হয়। আপনি যদি এই এবং উদাহরণস্বরূপ একটি + (বি + সি) এর মধ্যে পার্থক্য বলতে পারেন তবে সংকলকটি অর্ডার পরিবর্তন করতে পারে না। আপনি যদি পার্থক্যটি বলতে না পারেন, তবে সংকলকটি অর্ডার পরিবর্তন করতে মুক্ত, তবে এটি দুর্দান্ত, কারণ আপনি পার্থক্যটি বলতে পারবেন না।

আপনার উদাহরণে, খ = bit৪ বিট, ক এবং সি 32 বিটের সাহায্যে সংকলককে (বি + এ) + সি বা এমনকি (বি + সি) + এ মূল্যায়ন করার অনুমতি দেওয়া হবে কারণ আপনি পার্থক্যটি বলতে পারেন নি, তবে না (এ + সি) + বি কারণ আপনি পার্থক্য বলতে পারেন।

অন্য কথায়, সংকলকটিকে এমন কিছু করার অনুমতি নেই যা আপনার কোডটিকে যা করা উচিত তার থেকে আলাদা আচরণ করে। এটা আপনি মনে হয় এটা উত্পাদন করবে, অথবা আপনি মনে হয় যে তারা উত্পাদন করা উচিত যে কোড উত্পাদন করতে প্রয়োজন হয় না, কিন্তু কোড হবে আপনি ঠিক ফলাফল এটি করা উচিত দেব।


তবে একটি বড় সাবধানতা সহ; সংকলক কোনও অপরিজ্ঞাত আচরণ (এই ক্ষেত্রে ওভারফ্লো) অনুমান করার জন্য বিনামূল্যে। এটি ওভারফ্লো চেকটি কীভাবে if (a + 1 < a)অনুকূলিত করা যায় তার সমান ।
csiz

7
স্বাক্ষরযুক্ত ভেরিয়েবলগুলিতে @ সিএসজি ... স্বাক্ষরযুক্ত ভেরিয়েবলগুলিতে ওভারফ্লো শব্দার্থ (মোড়ানো) প্রায় ভাল-সংজ্ঞায়িত রয়েছে।
গ্যাভিন এস ইয়ানসি

7

মান থেকে উদ্ধৃতি :

[দ্রষ্টব্য: অপারেটরগুলি কেবল সাধারণ গাণিতিক নিয়ম অনুসারে পুনরায় সংগঠিত হতে পারে যেখানে অপারেটররা সত্যই সাহসী বা ক্রমবর্ধমান .7. উদাহরণস্বরূপ, নিম্নলিখিত খণ্ডে ক, খ;

/∗ ... ∗/
a = a + 32760 + b + 5;

এক্সপ্রেশন বিবৃতি ঠিক একই আচরণ করে

a = (((a + 32760) + b) + 5);

এই অপারেটরদের সাহচর্য এবং প্রাধান্যের কারণে। সুতরাং, যোগফলের ফলাফল (a + 32760) এর পরে খ-এর সাথে যুক্ত করা হবে এবং তারপরে ফলাফলটি 5 যুক্ত করা হবে যার ফলস্বরূপ ককে নির্ধারিত মান দেওয়া হয়। একটি মেশিনে ওভারফ্লোস একটি ব্যতিক্রম উত্পাদন করে এবং যেখানে কোনও ইন্টের দ্বারা প্রতিনিধিত্বযোগ্য মানগুলির পরিসীমা [-32768, + 32767] হয়, প্রয়োগটি এই এক্সপ্রেশনটিকে আবার লিখতে পারে না

a = ((a + b) + 32765);

যেহেতু যদি a এবং b এর মান যথাক্রমে -32754 এবং -15 হয় তবে a + b এর যোগফল একটি ব্যতিক্রম ঘটায় এবং মূল অভিব্যক্তিটি তা না করে; তেমনি এক্সপ্রেশনটি আবারও লেখা যায় না

a = ((a + 32765) + b);

অথবা

a = (a + (b + 32765));

যেহেতু a এবং b এর মানগুলি যথাক্রমে 4 এবং -8 বা -17 এবং 12 হতে পারে তবে যে কোনও মেশিনে ওভারফ্লোগুলি একটি ব্যতিক্রম তৈরি করে না এবং এতে অতিরিক্ত প্রবাহের ফলাফলগুলি বিপরীতমুখী হয়, উপরোক্ত অভিব্যক্তি বিবৃতিটি পারে উপরের যে কোনও উপায়ে প্রয়োগের মাধ্যমে পুনর্লিখন করা হবে কারণ একই ফলাফল আসবে। - শেষ নোট]


4

সংকলকগণ কি এ জাতীয় পুনঃক্রম করার অনুমতি দেয় বা আমরা ফলাফলের অসঙ্গতি লক্ষ্য করতে এবং অভিব্যক্তি আদেশটি যেমন রাখি তেমন তাদের বিশ্বাস করতে পারি?

সংকলকটি যদি একই ফলাফল দেয় কেবল তখনই পুনঃক্রম করতে পারে - এখানে যেমন আপনি পর্যবেক্ষণ করেছেন, তা হয় না।


কোনও ফাংশন টেম্পলেট লেখা সম্ভব, যদি আপনি এটি চান, যা std::common_typeযুক্ত করার আগে সমস্ত যুক্তি প্রচার করে - এটি নিরাপদ হবে, এবং কোনও যুক্তির আদেশ বা ম্যানুয়াল কাস্টিংয়ের উপর নির্ভর করবে না, তবে এটি বেশ চমত্কার।


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

1
যেমনটি আমি বলেছি, সুস্পষ্ট ingালাই ছাড়াই: বাম সংযোজনটি প্রথমে সঞ্চালিত হয়, অবিচ্ছেদ্য প্রচার ছাড়াই, এবং তাই মোড়ানো সাপেক্ষে। ফলাফলের যে উপরন্তু, সম্ভবত আবৃত এর, তাই তারপর উন্নীত uint64_tডান-সবচেয়ে মান ছাড়াও জন্য।
বেহুদা

বিধি-বিধান সম্পর্কে আপনার ব্যাখ্যা সম্পূর্ণ ভুল। উদাহরণস্বরূপ সি ভাষাটি বিমূর্ত মেশিনে কী কী অপারেশন হওয়া উচিত তা নির্দিষ্ট করে। "বিস্ময়কর" নিয়ম যতক্ষণ না কেউ ততক্ষণ পার্থক্য বলতে না পারে তা একেবারে যা করার তা করতে দেয়।
gnasher729

যার অর্থ সংকলকটি যতক্ষণ চাইবে যা করতে পারে ফলাফল ফলাফল হিসাবে বাম-সহযোগীতা এবং পাটিগণিত রূপান্তর বিধি দ্বারা নির্ধারিত হিসাবে নির্ধারিত।
25:25

1

এটি বিট প্রস্থের উপর নির্ভর করে unsigned/int

নীচের 2 টি একই নয় (যখন unsigned <= 32বিটস)। u32_x + u32_y0 হয়।

u64_a = 0; u32_x = 1; u32_y = 0xFFFFFFFF;
uint64_t u64_z = u32_x + u64_a + u32_y;
uint64_t u64_z = u32_x + u32_y + u64_a;  // u32_x + u32_y carry does not add to sum.

তারা একই (যখন unsigned >= 34বিট)। পূর্ণসংখ্যার প্রচারের কারণে u32_x + u32_y বিট গণিতে অতিরিক্ত সংযোজন ঘটে। আদেশ অপ্রাসঙ্গিক।

এটি ইউবি (যখন unsigned == 33বিটস) হয়। ইন্টিজার প্রচারগুলি স্বাক্ষরিত 33-বিট গণিত এবং স্বাক্ষরিত ওভারফ্লোটি ইউবি হওয়ার কারণে সংযোজন ঘটায়।

সংকলকগণ কি এই জাতীয় পুনঃক্রম করতে অনুমতি দেয় ...?

(32 বিট গণিত): পুনরায় অর্ডার হ্যাঁ, কিন্তু একই ফলাফল ঘটতে হবে, তাই যে পুনরায় ক্রম ওপি প্রস্তাব। নীচে একই

// Same
u32_x + u64_a + u32_y;
u64_a + u32_x + u32_y;
u32_x + (uint64_t) u32_y + u64_a;
...

// Same as each other below, but not the same as the 3 above.
uint64_t u64_z = u32_x + u32_y + u64_a;
uint64_t u64_z = u64_a + (u32_x + u32_y);

... ফলাফলের অসঙ্গতি লক্ষ্য করার জন্য এবং অভিব্যক্তিটির আদেশটি যেমন রাখে আমরা কি তাদের বিশ্বাস করতে পারি?

হ্যাঁ বিশ্বাস করুন, তবে ওপির কোডিং লক্ষ্য ক্রিস্টাল পরিষ্কার নয়। করা উচিত u32_x + u32_yঅবদান বহন? ওপি যদি সেই অবদান চায়, কোড হওয়া উচিত

uint64_t u64_z = u64_a + u32_x + u32_y;
uint64_t u64_z = u32_x + u64_a + u32_y;
uint64_t u64_z = u32_x + (u32_y + u64_a);

কিন্তু না

uint64_t u64_z = u32_x + u32_y + u64_a;
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.