c - কেন পূর্ণসংখ্যা বিভাগ দ্বারা-1(নেতিবাচক এক) ফলাফল এফপাইতে আসে?




gcc x86 (4)

আমার কাছে সি কোডের কিছু আপাতদৃষ্টিতে অদ্ভুত আচরণ (x86 এ চলছে) কাটিয়ে ওঠার একটি কার্যভার রয়েছে। আমি সহজেই অন্য সব কিছু শেষ করতে পারি তবে এটি আমাকে সত্যই বিভ্রান্ত করেছে।

কোড স্নিপেট 1 আউটপুট -2147483648

int a = 0x80000000;
int b = a / -1;
printf("%d\n", b);

কোড স্নিপেট 2 আউটপুট কিছুই দেয় না এবং একটি Floating point exception দেয়

int a = 0x80000000;
int b = -1;
int c = a / b;
printf("%d\n", c);

কোড স্নিপেট 1 ( 1 + ~INT_MIN == INT_MIN ) এর ফলাফলের কারণটি আমি ভালভাবে জানি, তবে আমি কীভাবে 1 + ~INT_MIN == INT_MIN জেনারেট -1 দ্বারা পূর্ণসংখ্যার বিভাগ 1 + ~INT_MIN == INT_MIN পারি তা আমি বেশ বুঝতে পারি না, বা আমি আমার অ্যান্ড্রয়েড ফোনে এটি পুনরুত্পাদন করতে পারি না (AArch64) , জিসিসি 7.2.0)। কোড 2 কেবল কোনও ব্যতিক্রম ছাড়াই কোড 1 এর সমান আউটপুট দেয়। এটি কি x86 প্রসেসরের একটি লুকানো বাগ বৈশিষ্ট্য?

অ্যাসাইনমেন্টটি অন্য কিছু জানায় নি (সিপিইউ আর্কিটেকচার সহ), তবে যেহেতু পুরো কোর্সটি একটি ডেস্কটপ লিনাক্স ডিস্ট্রো ভিত্তিক, তাই আপনি নিরাপদে ধরে নিতে পারেন এটি একটি আধুনিক x86।

সম্পাদনা করুন : আমি আমার বন্ধুর সাথে যোগাযোগ করেছি এবং তিনি উবুন্টু 16.04 (ইন্টেল কাবি লেক, জিসিসি 6.3.0) কোডটি পরীক্ষা করেছেন। ফলাফল নির্ধারিত যাই হোক না কেনের সাথে সামঞ্জস্যপূর্ণ (কোড 1 আউটপুট উল্লিখিত জিনিসটি এবং কোড 2 এফপিইতে ক্র্যাশ হয়েছিল)।


উভয় ক্ষেত্রেই অদ্ভুত, কারণ প্রথমটি -2147483648 -1 দ্বারা ভাগ করে এবং -2147483648 উচিত, আপনি যে ফলাফলটি পাচ্ছেন তা নয়।

0x80000000 একটি 32 বিট আর্কিটেকচারে একটি বৈধ int সংখ্যা নয় যা দুটি সংখ্যার পরিপূরক হিসাবে সংখ্যার প্রতিনিধিত্ব করে। যদি আপনি এর নেতিবাচক মান গণনা করেন তবে আপনি এটিতে আবার পাবেন, কারণ এর শূন্যের কাছাকাছি কোনও বিপরীত সংখ্যা নেই। আপনি যখন স্বাক্ষরিত পূর্ণসংখ্যার সাথে পাটিগণিত করেন, এটি পূর্ণসংখ্যা সংযোজন এবং বিয়োগের জন্য ভাল কাজ করে (সর্বদা যত্ন সহকারে, আপনি যখন কোনও প্রকারের মধ্যে সবচেয়ে বড় মান যোগ করেন তখন আপনি নিরাপদে) তবে আপনি এটির গুণক বা বিভাজনে নিরাপদে ব্যবহার করতে পারবেন না। সুতরাং এক্ষেত্রে আপনি অনির্ধারিত আচরণটি চালাচ্ছেন । আপনি সর্বদা স্বাক্ষরিত পূর্ণসংখ্যার সাথে ওভারফ্লোতে অনির্ধারিত আচরণ (বা বাস্তবায়িত সংজ্ঞায়িত আচরণ, যা একই, তবে একই নয়) এর আবেদন করেন, কারণ এটি বাস্তবায়নের ক্ষেত্রে প্রয়োগগুলি ব্যাপকভাবে পরিবর্তিত হয়।

সংঘটিত কিছু করতে বা কিছুই করার নিখুঁত হওয়ায় আমি কী ঘটছে (কোনও বিশ্বাসের সাথে না) তা বোঝানোর চেষ্টা করব।

0x80000000 , 0x80000000 হিসাবে দুটি এর পরিপূরক হিসাবে প্রতিনিধিত্ব করা হয়

1000_0000_0000_0000_0000_0000_0000

যদি আমরা এই সংখ্যাটি পরিপূরক করি তবে আমরা পাই (প্রথমে সমস্ত বিট পরিপূরক, তারপরে একটি যুক্ত করুন)

0111_1111_1111_1111_1111_1111_1111 + 1 =>
1000_0000_0000_0000_0000_0000_0000  !!!  the same original number.

আশ্চর্যজনকভাবে একই সংখ্যা .... আপনার একটি উপচে পড়েছিল (সাইন পরিবর্তন করার সময় আমরা যখন ভেসে উঠলাম এই সংখ্যাটির কোনও সদৃশ ইতিবাচক মান নেই) তখন আপনি সাইন বিটটি বের করে, মাস্কিংয়ের মাধ্যমে

1000_0000_0000_0000_0000_0000_0000 &
0111_1111_1111_1111_1111_1111_1111 =>
0000_0000_0000_0000_0000_0000_0000

যা বিভাজক হিসাবে আপনি ব্যবহার করেন তা শূন্য ব্যতিক্রম দ্বারা বিভাজনের দিকে পরিচালিত করে।

তবে আমি আগেই বলেছি, এটি আপনার সিস্টেমে যা ঘটতে পারে তা নিশ্চিত, তবে নিশ্চিত নন, যেমনটি স্ট্যান্ডার্ডটি বলে এটি এটি অপরিজ্ঞাত আচরণ এবং সুতরাং, আপনি আপনার কম্পিউটার / সংকলক থেকে যে কোনও ভিন্ন আচরণ পেতে পারেন।

নোট 1

সংকলকটি যেমন উদ্বিগ্ন, এবং মান প্রয়োগ করা আবশ্যক 0x8000...000 বৈধ পরিসীমা সম্পর্কে কিছুই বলে না (স্ট্যান্ডার্ডটি সাধারণত 0x8000...000 এর পরিপূরক আর্কিটেকচারে 0x8000...000 অন্তর্ভুক্ত করে না) 0x800...000 সঠিক আচরণ 0x800...000 দুইটির পরিপূরক আর্কিটেকচারের মধ্যে 0x800...000 হওয়া উচিত, কারণ এর ধরণের সংখ্যার পূর্ণসংখ্যার জন্য এটির বৃহত্তম পরম মান থাকে, যখন কোনও সংখ্যাকে বিভাজন করার সময় 0 ফলাফল দেয়। তবে হার্ডওয়্যার বাস্তবায়নগুলি সাধারণত এ জাতীয় সংখ্যায় বিভাজন করতে দেয় না (তাদের মধ্যে অনেকে স্বাক্ষরিত পূর্ণসংখ্যা বিভাগ বাস্তবায়ন করে না, তবে এটি স্বাক্ষরবিহীন বিভাগ থেকে অনুকরণ করে, তাই অনেকেই কেবল চিহ্নগুলি আহরণ করে এবং স্বাক্ষরবিহীন বিভাগ করেন) যার জন্য একটি প্রয়োজনীয় বিভাগের আগে চেক করুন, এবং মানটি অপরিজ্ঞাত আচরণ হিসাবে বলেছে, বাস্তবায়নের ক্ষেত্রে অবাধে এ জাতীয় চেক এড়াতে দেওয়া হয় এবং সেই সংখ্যার দ্বারা বিভাজনকে বঞ্চিত করা হয় । তারা 0x8000...001 থেকে 0xffff...fff , এবং তারপরে 0x000..0000 থেকে 0x7fff...ffff , 0x8000...0000 অবৈধ হিসাবে প্রত্যাখ্যান করে পূর্ণসংখ্যার পরিসর নির্বাচন করে select


এখানে চারটি জিনিস চলছে:

  • gcc -O0 আচরণ আপনার দুটি সংস্করণের মধ্যে পার্থক্য ব্যাখ্যা করে। (যখন clang -O0 এগুলি উভয়টি idiv দিয়ে idiv করতে ঘটে)। এবং কেন আপনি সংকলন-ধ্রুবক অপারেশন সহ এটি পেতে।
  • x86 idiv ফল্টিং আচরণ বনাম এআরএম বিভাগের নির্দেশের আচরণ
  • যদি পূর্ণসংখ্যার গণিতের ফলাফল সিগন্যালে পৌঁছে দেওয়া হয়, তবে পসিক্সের এটিকে সিএফএফপিই করা দরকার: কোন প্ল্যাটফর্মে শূন্য দ্বারা পূর্ণসংখ্যা বিভাজন একটি ভাসমান পয়েন্ট ব্যতিক্রমকে ট্রিগার করে? তবে পসিক্সের কোনও নির্দিষ্ট পূর্ণসংখ্যার ক্রিয়াকলাপের জন্য ট্র্যাপিংয়ের প্রয়োজন হয় না । (এই কারণেই এটি x86 এবং এআরএমকে আলাদা হওয়ার অনুমতি দেয়)।

    সিঙ্গেল ইউনিক্স স্পেসিফিকেশন SIGFPE কে "ত্রুটিযুক্ত পাটিগণিত অপারেশন" হিসাবে সংজ্ঞায়িত করে । বিভ্রান্তিকরভাবে এটি ভাসমান পয়েন্টের নামে নামকরণ করা হয়েছে, তবে এফপিইউর সাথে একটি স্বাভাবিক সিস্টেমে এটির ডিফল্ট অবস্থায় কেবল পূর্ণসংখ্যার গণিতই এটি উত্থাপন করে। X86 এ, কেবল পূর্ণসংখ্যা বিভাগ। এমআইপিএসে, একটি সংকলক স্বাক্ষরিত গণিতের জন্য addu পরিবর্তে add ব্যবহার করতে পারে, যাতে আপনি স্বাক্ষরিত অ্যাড ওভারফ্লোতে ফাঁদ পেতে পারেন। ( addu এমনকি স্বাক্ষরিত হওয়ার জন্য addu ব্যবহার করে তবে একটি সংজ্ঞায়িত আচরণের সনাক্তকারী add ব্যবহার করতে পারে))

  • সি অপরিজ্ঞাত আচরণ বিধিমালা (স্বাক্ষরিত ওভারফ্লো এবং বিভাগ বিশেষত) যা সিসিকে এমিট কোড দেয় যা সেই ক্ষেত্রে ফাঁদে যেতে পারে।

কোনও বিকল্প নেই সহ gcc -O0

-O0 সংকলনের সময় হ্রাস করুন এবং -O0 প্রত্যাশিত ফলাফলগুলি তৈরি করুন । এটি ডিফল্ট।

এটি আপনার দুটি সংস্করণের মধ্যে পার্থক্য ব্যাখ্যা করে:

কেবল gcc -O0 অপ্টিমাইজ করার চেষ্টা করে না, এটি সক্রিয়ভাবে asm তৈরি করতে ডি-অপ্টিমাইজ করে যা একটি ফাংশনের মধ্যে প্রতিটি সি স্টেটমেন্টকে স্বতন্ত্রভাবে প্রয়োগ করে। এটি gdb এর jump কমান্ডটিকে নিরাপদে কাজ করতে দেয়, আপনাকে ফাংশনটির মধ্যে একটি অন্য লাইনে ঝাঁপিয়ে পড়ে এবং আপনি সি সি উত্সের আশেপাশে ঝাঁপিয়ে পড়ে এমন আচরণ করতে দেয়।

এটি বিবৃতিগুলির মধ্যে ভেরিয়েবলের মান সম্পর্কে কিছুও ধরে নিতে পারে না, কারণ আপনি set b = 4 দিয়ে ভেরিয়েবল পরিবর্তন করতে পারেন। পারফরম্যান্সের জন্য এটি স্পষ্টতই বিপর্যয়কর, কারণ এই কারণেই -O0 কোডটি স্বাভাবিক কোডের চেয়ে কয়েকগুণ ধীর হয়ে যায় এবং কেন -O0 জন্য -O0 অপ্টিমাইজ করা মোট -O0 । এটি স্টোরিং / পুনরায় লোড করা এবং এমনকি সবচেয়ে সুস্পষ্ট অপ্টিমাইজেশনের অভাবের কারণে -O0 এএসএম আউটপুটটি সত্যই গোলমাল এবং পড়তে কোনও মানুষের পক্ষে শক্ত হয়

int a = 0x80000000;
int b = -1;
  // debugger can stop here on a breakpoint and modify b.
int c = a / b;        // a and b have to be treated as runtime variables, not constants.
printf("%d\n", c);

এই বিবৃতিগুলির জন্য asm পেতে গডবোল্ট সংকলক এক্সপ্লোরারকে আমি আপনার কোডগুলি ফাংশনের ভিতরে রেখেছি

a/b মূল্যায়ন করতে, gcc -O0 মেমরি থেকে a এবং b পুনরায় লোড করার জন্য কোড নির্গত করতে হবে এবং তাদের মান সম্পর্কে কোনও অনুমান করা উচিত নয়।

তবে int c = a / -1; , আপনি কোনও ডিবাগার দিয়ে -1 পরিবর্তন করতে পারবেন না , সুতরাং জিসিসি সেই বিবৃতিটি একইভাবে প্রয়োগ করতে পারে যেমন এটি int c = -a; প্রয়োগ করবে int c = -a; , একটি x86 neg w0, w0 বা AArch64 neg w0, w0 নির্দেশ সহ, লোড দ্বারা বেষ্টিত (ক) / স্টোর (সি)। এআরএম 32 এ, এটি একটি rsb r3, r3, #0 (বিপরীত বিয়োগ: r3 = 0 - r3 )।

তবে, ক্ল্যাং -O0 -O0 সেই অপ্টিমাইজেশনটি করে না। এটি এখনও a / -1 জন্য idiv ব্যবহার করে, সুতরাং উভয় সংস্করণ idiv সহ x86 এ দোষী হবে। জিসিসি কেন আদৌ "অনুকূলিত হয়"? জিসিসিতে সমস্ত অপ্টিমাইজেশন বিকল্পগুলি অক্ষম দেখুন। জিসিসি সর্বদা অভ্যন্তরীণ উপস্থাপনার মাধ্যমে রূপান্তর করে এবং -O0 বাইনারি তৈরি করতে প্রয়োজনীয় ন্যূনতম পরিমাণ কাজ। এটিতে "বোবা এবং আক্ষরিক" মোড নেই যা যতটা সম্ভব উত্সটিকে যতটা সম্ভব উত্স হিসাবে তৈরি করার চেষ্টা করে।

x86 idiv বনাম idiv 64 sdiv :

x86-64 ':

    # int c = a / b  from x86_fault()
    mov     eax, DWORD PTR [rbp-4]
    cdq                                 # dividend sign-extended into edx:eax
    idiv    DWORD PTR [rbp-8]           # divisor from memory
    mov     DWORD PTR [rbp-12], eax     # store quotient

imul r32,r32 -এর বিপরীতে imul r32,r32 কোনও 2- idiv যা লভ্যাংশের উপরের অর্ধেক ইনপুট রাখে না। যাইহোক, এটি গুরুত্বপূর্ণ নয় যে; edx সাইন বিটের edx = অনুলিপিগুলি সহ কেবল ব্যবহার করছে, সুতরাং এটি সত্যই একটি edx / edx => edx ভাগফল + বাকী করছে। idiv , idiv # idiv উত্থাপন করেছে:

  • বিভাজক = 0
  • স্বাক্ষরিত ফলাফল (ভাগফল) গন্তব্যের পক্ষে খুব বড়।

ওভারফ্লো সহজেই ঘটতে পারে যদি আপনি বিভাজনের সম্পূর্ণ পরিসীমা ব্যবহার করেন, উদাহরণস্বরূপ int result = long long / int ইন্টি একক b৪ বি / ৩২ বি => ৩২ বি বিভাগ সহ। তবে সিসিটি সেই অপ্টিমাইজেশনটি করতে পারে না কারণ এটি সি কোড পূর্ণসংখ্যা প্রচারের নিয়মগুলি অনুসরণ করার পরিবর্তে এবং একটি division৪-বিট বিভাগ এবং তারপরে ইনটকে সংক্ষিপ্তকরণের পরিবর্তে কোড তৈরি করার অনুমতি দেয় না। এটি এমন ক্ষেত্রে এমনকি #DE বড় হিসাবে পরিচিত যে এটি #DE করতে পারে না এমন ক্ষেত্রেও এটি অপ্টিমাইজ করে না

INT_MIN / -1 বিভাগ ( cdq ) করার সময়, কেবলমাত্র ইনপুটটি প্রবাহিত করতে পারে INT_MIN / -1 । "সঠিক" 0x80000000 একটি 33-বিট স্বাক্ষরিত পূর্ণসংখ্যা, অর্থাত্ ইতিবাচক 0x80000000 এটি একটি ইতিবাচক 2 এর পরিপূরক স্বাক্ষর পূর্ণ পূর্ণ পূর্ণসংখ্যার জন্য একটি শূন্য চিহ্নের বিট সহ positive যেহেতু এটি idiv ফিট হয় না, idiv একটি #DE ব্যতিক্রম উত্থাপন করে। কার্নেলটি পরে SIGFPE সরবরাহ করে।

AArch64:

    # int c = a / b  from x86_fault()  (which doesn't fault on AArch64)
    ldr     w1, [sp, 12]
    ldr     w0, [sp, 8]          # 32-bit loads into 32-bit registers
    sdiv    w0, w1, w0           # 32 / 32 => 32 bit signed division
    str     w0, [sp, 4]

এএএএএফসিটি, এআরএম হার্ডওয়্যার বিভাগ নির্দেশাবলী শূন্য দ্বারা ভাগ করার জন্য বা INT_MIN / -1 এর জন্য ব্যতিক্রম বাড়ায় না। বা কমপক্ষে, কিছু এআরএম সিপিইউ করে না। এআরএম OMAP3515 প্রসেসরে শূন্য ব্যতিক্রম দ্বারা বিভাজন

AArch64 sdiv ডকুমেন্টেশন কোনও ব্যতিক্রম উল্লেখ করে না।

তবে পূর্ণসংখ্যা বিভাগের সফ্টওয়্যার বাস্তবায়নগুলি উত্থাপন করতে পারে: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka4061.html (জিসিসি ডিফল্ট অনুসারে এআরএম 32 তে বিভাগের জন্য একটি লাইব্রেরি কল ব্যবহার করে, যদি আপনি এইচডাব্লু বিভাগ থাকে এমন একটি এমসিপু সেট না করেন।)

সি অপরিবর্তিত আচরণ।

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

ইউবির পরিণতি সম্পর্কে আরও:

অপ্টিমাইজেশন সক্ষম করার সাথে , সংকলক ধরে নিতে পারে যে a/b চালায় তখনও a এবং b সেট মান রয়েছে। এরপরে এটি প্রোগ্রামটির অপরিবর্তিত আচরণ রয়েছে এবং এটি যা চায় তা করতে পারে। INT_MIN যেমন INT_MIN থেকে তৈরি INT_MIN পছন্দ করে।

2 এর পরিপূরক সিস্টেমে সর্বাধিক-নেতিবাচক সংখ্যাটি তার নিজস্ব negativeণাত্মক। এটি 2 এর পরিপূরকগুলির জন্য একটি বাজে কর্নার-কেস, কারণ এর অর্থ abs(x) এখনও নেতিবাচক হতে পারে। https://en.wikipedia.org/wiki/Two%27s_complement#Most_negative_number

int x86_fault() {
    int a = 0x80000000;
    int b = -1;
    int c = a / b;
    return c;
}

x86-64 এর জন্য gcc6.3 -O3 দিয়ে gcc6.3 -O3

x86_fault:
    mov     eax, -2147483648
    ret

তবে clang5.0 -O3 সংকলন করে (এমনকি কোনও clang5.0 -O3 সহ কোনও সতর্কতা ছাড়াই):

x86_fault:
    ret

অপরিজ্ঞাত আচরণটি সত্যই সম্পূর্ণ অপরিজ্ঞাত। কম্পাইলাররা ফাংশন প্রবেশের সময় যেকোন ময়লা আবর্জনা ফিরিয়ে দেওয়া, বা একটি এনইউএলএল পয়েন্টার এবং একটি অবৈধ নির্দেশাবলীতে লোড সহ যা কিছু মনে করতে পারে তা করতে পারে। যেমন x86-64 এর জন্য gcc6.3 -O3 সহ:

int *local_address(int a) {
    return &a;
}

local_address:
    xor     eax, eax     # return 0
    ret

void foo() {
    int *p = local_address(4);
    *p = 2;
}

 foo:
   mov     DWORD PTR ds:0, 0     # store immediate 0 into absolute address 0
   ud2                           # illegal instruction

-O0 সাথে আপনার কেস সংকলনের সময় -O0 ইউবি দেখতে দেয়নি, সুতরাং আপনি "প্রত্যাশিত" এসএম আউটপুট পেয়েছেন।

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


idiv আপনি যদি idiv অপারেশনটি ব্যবহার করে ভাগ করে idiv (যা ধ্রুবক যুক্তির জন্য সত্যই প্রয়োজনীয় নয়, এমনকি ভেরিয়েবল-টু- INT_MIN / -1 নয়, তবে যাই হোক না কেন ঘটেছে), INT_MIN / -1 মধ্যে একটি হল যে #DE এ ফলাফল (বিভাজন ত্রুটি)। ভাগফলের সীমার বাইরে থাকা সত্যিই এটির একটি বিশেষ ঘটনা, সাধারণভাবে এটি সম্ভব কারণ idiv বিভাজক দ্বারা একটি অতিরিক্ত-বিস্তৃত লভ্যাংশ ভাগ করে দেয়, তাই অনেকগুলি সংমিশ্রণে ওভারফ্লো হয় - তবে INT_MIN / -1 একমাত্র কেস যা একটি নয় ডিভ বাই বাই 0 যা আপনি সাধারণত উচ্চ স্তরের ভাষাগুলি থেকে সাধারণত অ্যাক্সেস করতে পারেন যেহেতু তারা সাধারণত অতিরিক্ত-প্রশস্ত-লভ্যাংশের ক্ষমতা প্রকাশ করে না।

লিনাক্স বিরক্তিকরভাবে সিডিএফপিইতে #DE কে মানচিত্র করে, যা সম্ভবত এটির সাথে প্রথমবার যারা আচরণ করেছে তাদের সবাইকে বিভ্রান্ত করেছে।


নির্ধারিত আচরণের সাথে খুব bad জিনিস ঘটতে পারে এবং কখনও কখনও তা ঘটে।

আপনার প্রশ্নের সিতে কোনও ধারণা নেই ( ইউবিতে ল্যাটনার পড়ুন)। তবে আপনি এসেম্বলারের কোড পেতে পারেন (যেমন, gcc -O -fverbose-asm -Sgcc -O -fverbose-asm -S দ্বারা উত্পাদিত) এবং মেশিন কোড আচরণ সম্পর্কে যত্নশীল।

X86-64 এ লিনাক্স পূর্ণসংখ্যার ওভারফ্লো (এবং শূন্য দ্বারা পূর্ণসংখ্যা বিভাগ, আইআইআরসি) একটি SIGFPE সিগন্যাল দেয়। signal(7) দেখুন signal(7)

বিটিডাব্লু, পাওয়ারপিসি পূর্ণসংখ্যা বিভাগের শূন্য দ্বারা মেশিন পর্যায়ে -1 দেওয়ার গুজব রয়েছে (তবে কিছু সি সংকলক সেই ক্ষেত্রে পরীক্ষার জন্য অতিরিক্ত কোড উত্পন্ন করে)।

আপনার প্রশ্নের কোডটি সি তে অপরিবর্তিত আচরণ The উত্পন্ন এসেমব্লার কোডটির কিছু নির্ধারিত আচরণ রয়েছে ( ISA এবং প্রসেসরের উপর নির্ভর করে)।

(অ্যাসাইনমেন্টটি আপনাকে ইউবি সম্পর্কে আরও পড়ার জন্য তৈরি করা হয়েছে, উল্লেখযোগ্যভাবে ল্যাটারের ব্লগ , যা আপনার একেবারে পড়া উচিত)






floating-point-exceptions