অপ্টিমাইজেশান সক্ষম সহ বিভিন্ন ভাসমান পয়েন্ট ফলাফল - সংকলক বাগ?


109

নীচের কোডটি ভিজ্যুয়াল স্টুডিও ২০০৮ এ অপটিমাইজেশন সহ এবং ছাড়া কাজ করে। তবে এটি কেবল অপ্টিমাইজেশন (O0) ছাড়াই g ++ এ কাজ করে।

#include <cstdlib>
#include <iostream>
#include <cmath>

double round(double v, double digit)
{
    double pow = std::pow(10.0, digit);
    double t = v * pow;
    //std::cout << "t:" << t << std::endl;
    double r = std::floor(t + 0.5);
    //std::cout << "r:" << r << std::endl;
    return r / pow;
}

int main(int argc, char *argv[])
{
    std::cout << round(4.45, 1) << std::endl;
    std::cout << round(4.55, 1) << std::endl;
}

আউটপুটটি হওয়া উচিত:

4.5
4.6

তবে অপ্টিমাইজেশান ( O1- O3) সহ জি ++ আউটপুট আসবে:

4.5
4.5

যদি আমি volatileটির আগে কীওয়ার্ডটি যুক্ত করি তবে এটি কাজ করে, তাই কোনও ধরণের অপ্টিমাইজেশন বাগ থাকতে পারে?

জি ++ 4.1.2 এবং 4.4.4 এ পরীক্ষা করুন।

আইডিয়োন-এর ফলাফল এখানে: http://ideone.com/Rz937

এবং g ++ এ আমি যা বিকল্প পরীক্ষা করি তা সহজ:

g++ -O2 round.cpp

আরও আকর্ষণীয় ফলাফল, এমনকি আমি /fp:fastভিজ্যুয়াল স্টুডিও ২০০৮-এর বিকল্পটি চালু করি , ফলাফলটি এখনও সঠিক।

আরও প্রশ্ন:

আমি ভাবছিলাম, আমি কি সবসময় -ffloat-storeবিকল্পটি চালু করব ?

কারণ আমি পরীক্ষিত জি ++ সংস্করণটি সেন্টোস / রেড হ্যাট লিনাক্স 5 এবং সেন্টোস / রেডহ্যাট 6 দিয়ে পাঠানো হয়েছে

আমি এই প্ল্যাটফর্মগুলির অধীনে আমার অনেকগুলি প্রোগ্রাম সংকলন করেছি এবং আমি উদ্বিগ্ন যে এটি আমার প্রোগ্রামগুলির মধ্যে অপ্রত্যাশিত বাগ তৈরি করবে। আমার সমস্ত সি ++ কোড এবং ব্যবহৃত লাইব্রেরিগুলিতে তাদের এ জাতীয় সমস্যা আছে কিনা তা অনুসন্ধান করা কিছুটা কঠিন বলে মনে হচ্ছে। যেকোনো পরামর্শ?

এমনকি কেন /fp:fastচালু করা হয়েছে, ভিজ্যুয়াল স্টুডিও ২০০৮ এখনও কাজ করে? দেখে মনে হচ্ছে ভিজ্যুয়াল স্টুডিও ২০০৮ জি ++ এর চেয়ে এই সমস্যায় বেশি নির্ভরযোগ্য?


51
সমস্ত নতুন এসও ব্যবহারকারীদের কাছে: আপনি কীভাবে প্রশ্ন জিজ্ঞাসা করবেন এটি এটি। +1
টেনফোর

1
এফডাব্লুআইডাব্লু, আমি মিনি + ডাব্লু ব্যবহার করে জি ++ 4.5.0 দিয়ে সঠিক আউটপুট পাচ্ছি।
স্টিভ ব্ল্যাকওয়েল

2
আইডিয়োন 4.3.4 আদর্শের ব্যবহার করে / বি 8 ভিএক্সজি
ড্যানিয়েল এ। হোয়াইট

5
আপনার মনে রাখা উচিত যে আপনার রুটিনটি সমস্ত ধরণের আউটপুট দিয়ে নির্ভরযোগ্যভাবে কাজ করার সম্ভাবনা নেই। একটি পূর্ণসংখ্যার দ্বিগুণ গোল করার বিপরীতে, এটি সত্যিকার অর্থে যে সমস্ত আসল সংখ্যা উপস্থাপন করা যায় না তাই এটির মতো আরও বেশি বাগ পাওয়ার আশা করা উচিত to
Jakub Wieczorek

2
যারা বাগটি পুনরুত্পাদন করতে পারবেন না: মন্তব্য করা আউট ডিবাগ স্ট্যাম্টগুলিকে সন্দেহজনক করবেন না, তারা ফলাফলকে প্রভাবিত করে।
এন। 'সর্বনাম' মি।

উত্তর:


91

ইন্টেল x86 প্রসেসরগুলি অভ্যন্তরীণভাবে 80-বিট প্রসারিত নির্ভুলতা ব্যবহার করে, যেখানে doubleসাধারণত 64৪-বিট প্রস্থ থাকে। বিভিন্ন অপ্টিমাইজেশনের স্তরগুলি সিপিইউ থেকে ভাসমান পয়েন্টের মানগুলিকে মেমরির মধ্যে সংরক্ষণ করার জন্য প্রায়শই প্রভাব ফেলে এবং এভাবে 80-বিট যথার্থ থেকে 64-বিট যথার্থ হয়ে যায়।

-ffloat-storeবিভিন্ন অপটিমাইজেশন স্তরগুলির সাথে একই ভাসমান পয়েন্টের ফলাফল পেতে জিসিসি বিকল্পটি ব্যবহার করুন ।

বিকল্পভাবে, long doubleটাইপটি ব্যবহার করুন , যা সাধারণত 80-বিট থেকে 64-বিট নির্ভুলতার দিকে গোল না এড়াতে জিসিসি-তে সাধারণত 80-বিট প্রস্থ।

man gcc এটি সব বলছে:

   -ffloat-store
       Do not store floating point variables in registers, and inhibit
       other options that might change whether a floating point value is
       taken from a register or memory.

       This option prevents undesirable excess precision on machines such
       as the 68000 where the floating registers (of the 68881) keep more
       precision than a "double" is supposed to have.  Similarly for the
       x86 architecture.  For most programs, the excess precision does
       only good, but a few programs rely on the precise definition of
       IEEE floating point.  Use -ffloat-store for such programs, after
       modifying them to store all pertinent intermediate computations
       into variables.

X86_64 এ সংকলকগুলি ডিফল্টর জন্য floatএবং এসএসই রেজিস্টারগুলি ব্যবহার doubleকরে যাতে কোনও প্রসারিত যথার্থতা ব্যবহার না করা হয় এবং এই সমস্যাটি না ঘটে।

gccসংকলক বিকল্প এটি-mfpmath নিয়ন্ত্রণ করে।


20
আমি মনে করি এটিই উত্তর। ধ্রুবক 4.55 4.54999999999999 এ রূপান্তরিত হয় যা 64 বিটের নিকটতম বাইনারি উপস্থাপনা; 10 দিয়ে গুণিত করুন এবং আবার 64৪ বিটে গোল করুন এবং আপনি 45.5 পাবেন। আপনি যদি 80-বিট রেজিস্ট্রারে রেখে গোলাকার পদক্ষেপটি এড়িয়ে যান তবে 4545999999999999 এ শেষ করবেন।
মার্ক রান্সম

ধন্যবাদ, আমি এই বিকল্পটি জানি না। তবে আমি ভাবছিলাম, আমি কি সর্বদা -ফ্লোট-স্টোর বিকল্পটি চালু করব? কারণ আমি পরীক্ষিত জি ++ সংস্করণটি সেন্টোস / রেডহাট 5 এবং সেন্টোস / রেডহাট 6 দিয়ে পাঠানো হয়েছে I আমি এই প্ল্যাটফর্মগুলির অধীনে আমার অনেকগুলি প্রোগ্রাম সংকলন করেছি, এটি সম্পর্কে আমার উদ্বেগ যে আমার প্রোগ্রামগুলির মধ্যে অপ্রত্যাশিত বাগগুলি সৃষ্টি করবে।
বিয়ার

5
@ বিয়ার, ডিবাগ বিবৃতি সম্ভবত একটি রেজিস্টার থেকে মেমরির মধ্যে ফ্লাশ হওয়ার কারণ ঘটায়।
মার্ক রান্সম

2
@ ভাল, সাধারণত আপনার অ্যাপ্লিকেশনটি প্রসারিত নির্ভুলতা থেকে উপকৃত হওয়া উচিত, যদি না যখন এটি একটি bit৪-বিট ভাসমানের কম বা প্রবাহিত এবং উত্পাদন প্রত্যাশিত হয় তখন অত্যন্ত ক্ষুদ্র বা বিশাল মানের উপর পরিচালিত হয় inf। থাম্বের কোনও ভাল নিয়ম নেই, ইউনিট পরীক্ষাগুলি আপনাকে একটি নির্দিষ্ট উত্তর দিতে পারে।
ম্যাক্সিম এগারুশকিন

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

10

আউটপুটটি হওয়া উচিত: 4.5 6 4.6 যদি আপনার অসীম নির্ভুলতা থাকে বা আপনি যদি বাইনারি-ভিত্তিক ভাসমান পয়েন্ট উপস্থাপনার চেয়ে দশমিক ভিত্তিক ব্যবহার করে এমন কোনও ডিভাইস নিয়ে কাজ করে থাকেন তবে আউটপুটটি এটাই হবে। কিন্তু, আপনি না। বেশিরভাগ কম্পিউটার বাইনারি আইইইই ফ্লোটিং পয়েন্ট স্ট্যান্ডার্ড ব্যবহার করে।

যেমনটি ম্যাক্সিম ইয়েগুরুশকিন ইতিমধ্যে তাঁর উত্তরে উল্লেখ করেছেন, সমস্যার একটি অংশ হ'ল অভ্যন্তরীণভাবে আপনার কম্পিউটারটি একটি 80 বিট ভাসমান পয়েন্ট উপস্থাপনা ব্যবহার করছে। যদিও এটি সমস্যার একটি অংশ। সমস্যার ভিত্তি হ'ল n.nn5 ফর্মের যে কোনও সংখ্যার সঠিক বাইনারি ভাসমান উপস্থাপনা নেই। এই কোণার কেসগুলি সর্বদা অখাদ্য সংখ্যা।

আপনি যদি সত্যই চান যে আপনার রাউন্ডিংগুলি এই কোণার ক্ষেত্রে নির্ভরযোগ্যভাবে গোল করতে সক্ষম হতে পারে তবে আপনার একটি গোলাকার অ্যালগরিদম দরকার যা n.n5, n.nn5, বা n.nnn5, ইত্যাদিকে সম্বোধন করে (তবে এন 5 নয়) সর্বদা থাকে বেঠিক। কোণার কেসটি সন্ধান করুন যা নির্ধারণ করে যে কিছু ইনপুট মান চূড়ান্ত হয় বা নীচে এবং এই কোণার কেসের তুলনার ভিত্তিতে বৃত্তাকার আপ বা বৃত্তাকার-ডাউন মান প্রদান করে। এবং আপনার যত্ন নিতে হবে যে একটি অনুকূলিতকরণ সংকলকটি খুঁজে পাওয়া কোণার কেসটিকে প্রসারিত নির্ভুলতা রেজিস্টারে রাখবে না।

দেখুন এক্সেল কীভাবে সাফল্যের সাথে ভাসমান সংখ্যার অসম্পূর্ণতার পরেও গোল করে? যেমন একটি অ্যালগরিদমের জন্য।

অথবা আপনি কেবল এই সত্যটি নিয়েই বেঁচে থাকতে পারেন যে কোণার কেসগুলি কখনও কখনও ভুলক্রমে গোল হয়ে যায়।


6

বিভিন্ন সংকলক বিভিন্ন অপ্টিমাইজেশন সেটিংস আছে। সেই দ্রুততর অপ্টিমাইজেশন সেটিংসগুলির মধ্যে কয়েকটি আইইইই 754 অনুযায়ী কঠোর ভাসমান-পয়েন্ট নিয়ম বজায় রাখে না । ভিসুয়াল স্টুডিও একটি নির্দিষ্ট সেটিং রয়েছে /fp:strict, /fp:precise, /fp:fast, যেখানে /fp:fastকি করা যেতে পারে উপর মান লঙ্ঘন করে। আপনি দেখতে পাবেন যে এই পতাকাটি এই জাতীয় সেটিংসে অপ্টিমাইজেশন নিয়ন্ত্রণ করে। আপনি জিসিসিতে অনুরূপ সেটিংসও পেতে পারেন যা আচরণ পরিবর্তন করে।

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


4
-ffast-mathজিসিসির জন্য একটি সুইচ রয়েছে যা, এবং -Oউদ্ধৃতি দেওয়ার পরে এটি কোনও অপ্টিমাইজেশন স্তর দ্বারা চালু করা হয়নি : "এটি এমন প্রোগ্রামগুলির জন্য ভুল আউটপুট তৈরি করতে পারে যা গণিতের ক্রিয়াকলাপগুলির জন্য আইইইই বা আইএসও বিধি / স্পেসিফিকেশনের সঠিক প্রয়োগের উপর নির্ভর করে।"
মাদুর

@ ম্যাট: আমি চেষ্টা করেছি -ffast-mathএবং আমার আরও কয়েকটি জিনিস g++ 4.4.3এবং আমি এখনও সমস্যার পুনরুত্পাদন করতে অক্ষম।
এনপিই

ভাল: সাথে -ffast-mathআমি 4.5উভয় ক্ষেত্রে অপটিমাইজেশন স্তর এর চেয়ে বড় জন্য পেতে পারি 0
কেরেক এসবি

: (কারেকশন আমি পেতে 4.5সঙ্গে -O1এবং -O2কিন্তু না -O0এবং -O3জিসিসি 4.4.3, কিন্তু সঙ্গে -O1,2,3জিসিসি 4.6.1 মধ্যে।)
Kerrek এসবির

4

যারা বাগটি পুনরুত্পাদন করতে পারবেন না: মন্তব্য করা আউট ডিবাগ স্ট্যাম্টগুলিকে সন্দেহজনক করবেন না, তারা ফলাফলকে প্রভাবিত করে।

এটি বোঝায় যে সমস্যাটি ডিবাগের বিবৃতিগুলির সাথে সম্পর্কিত। এবং দেখে মনে হচ্ছে আউটপুট স্টেটমেন্ট চলাকালীন রেজিস্টারগুলিতে মানগুলি লোড করার ফলে গোলাকার ত্রুটি দেখা দিয়েছে, যার কারণে অন্যরা বুঝতে পেরেছেন যে আপনি এটি দিয়ে ঠিক করতে পারেন-ffloat-store

আরও প্রশ্ন:

আমি ভাবছিলাম, আমি কি সবসময় -ffloat-storeবিকল্পটি চালু করব ?

জেঠা হওয়ার উদ্দেশ্যে একটি কারণ যে কিছু প্রোগ্রামারদের চালু না হওয়া আবশ্যক -ffloat-store, অন্যথায় বিকল্প কোন অস্তিত্ব নেই হবে (অনুরূপভাবে, একটি কারণ যে কিছু প্রোগ্রামারদের হতে হবে না চালু -ffloat-store)। আমি সর্বদা এটি চালু বা সর্বদা বন্ধ করার পরামর্শ দেব না। এটিকে চালু করা কিছু অপ্টিমাইজেশনকে বাধা দেয়, তবে এটিকে বন্ধ করে দেওয়া আপনি যে ধরণের আচরণ করছেন তা মঞ্জুরি দেয়।

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

পরিবর্তে, আপনি যে সমস্যার সমাধান করতে চাইছেন তার অন্যান্য সমাধানগুলি সন্ধান করতে চাইতে পারেন (দুর্ভাগ্যক্রমে, কেনিগ প্রকৃত কাগজটির দিকে ইঙ্গিত করেনি, এবং আমি সত্যই এর পক্ষে একটি স্পষ্টত "প্রচলিত" জায়গা খুঁজে পাচ্ছি না, তাই আমি আপনাকে গুগলে প্রেরণ করতে হবে )।


যদি আপনি আউটপুট উদ্দেশ্যে গোল না করে থাকেন তবে আমি সম্ভবত std::modf()(ইন cmath) এবং std::numeric_limits<double>::epsilon()(ইন limits) এর দিকে নজর দেব । আসল round()ফাংশনটি নিয়ে ভাবনা , আমি বিশ্বাস করি std::floor(d + .5)যে এই ফাংশনে কল দিয়ে কলটি প্রতিস্থাপন করা আরও পরিষ্কার হবে :

// this still has the same problems as the original rounding function
int round_up(double d)
{
    // return value will be coerced to int, and truncated as expected
    // you can then assign the int to a double, if desired
    return d + 0.5;
}

আমি মনে করি এটি নিম্নলিখিত উন্নতির পরামর্শ দেয়:

// this won't work for negative d ...
// this may still round some numbers up when they should be rounded down
int round_up(double d)
{
    double floor;
    d = std::modf(d, &floor);
    return floor + (d + .5 + std::numeric_limits<double>::epsilon());
}

একটি সাধারণ দ্রষ্টব্য: std::numeric_limits<T>::epsilon()"সংখ্যায় সর্বনিম্ন সংখ্যার সাথে সংযুক্ত 1 যা 1 এর সমান নয় এমন একটি সংখ্যা তৈরি করে" defined আপনি সাধারণত "1" ব্যতীত অন্য সংখ্যার সাথে কাজ করছেন এই বিষয়টি জানতে অ্যাকাউন্ট সম্পর্কিত কোনও আপেক্ষিক অ্যাপসিলন (অর্থাত্ স্কেল এপসিলনটি ব্যবহার করতে হবে)। এর সমষ্টি d, .5এবং std::numeric_limits<double>::epsilon()1 কাছাকাছি হওয়া উচিত, তাই গোষ্ঠীবদ্ধ যে উপরন্তু মানে যে std::numeric_limits<double>::epsilon()আমরা যা করছি তার সঠিক মাপ সম্পর্কে হতে হবে। যদি কিছু হয় std::numeric_limits<double>::epsilon()তবে তা খুব বড় হবে (যখন তিনটির যোগফল একের চেয়ে কম হয়) এবং আমাদের যখন না করা উচিত তখন কিছু সংখ্যাকে গোল করে দিতে পারে।


আজকাল, আপনার বিবেচনা করা উচিত std::nearbyint()


একটি "আপেক্ষিক অ্যাপসিলন" বলা হয় 1 টি ইউলপ (শেষ স্থানে 1 ইউনিট)। x - nextafter(x, INFINITY)এক্স এর জন্য 1 টি ওলপ সম্পর্কিত (তবে এটি ব্যবহার করবেন না; আমি নিশ্চিত যে কোণার কেস রয়েছে এবং আমি কেবল এটি তৈরি করেছি)। epsilon() ইউএলপি-ভিত্তিক আপেক্ষিক ত্রুটি পেতে স্কেলিংয়ের উদাহরণটি সিপ্রেফারেন্স উদাহরণে রয়েছে
পিটার কর্ডেস

2
বিটিডাব্লু, 2016 এর উত্তরটি -ffloat-store: প্রথম স্থানে x87 ব্যবহার করবেন না। -mfpmath=sse -msse2এসএসই 2 গণিত (64-বিট বাইনারি, বা ক্রাস্টল পুরাতন 32-বিট বাইনারি তৈরির জন্য) ব্যবহার করুন, কারণ এসএসই / এসএসই 2-তে কোনও অতিরিক্ত নির্ভুলতা ছাড়াই অস্থায়ী অধ্যায় রয়েছে। doubleএবং floatএক্সএমএম রেজিস্টারগুলিতে ওয়ার্সগুলি সত্যই আইইইই 64-বিট বা 32-বিট ফর্ম্যাটে রয়েছে। (এক্স ৮87 এর মত নয়, যেখানে নিবন্ধগুলি সর্বদা 80-বিট থাকে এবং 32 বা 64 বিটের মেমোরি রাউন্ডে সঞ্চয় করে থাকে))
পিটার কর্ডেস

3

গৃহীত উত্তরটি সঠিক যদি আপনি কোনও x86 টার্গেটে সংকলন করে যাতে এসএসই 2 অন্তর্ভুক্ত থাকে না। সমস্ত আধুনিক x86 প্রসেসর এসএসই 2 সমর্থন করে, তাই আপনি যদি এটির সুবিধা নিতে পারেন তবে আপনার উচিত:

-mfpmath=sse -msse2 -ffp-contract=off

আসুন এটি ভেঙে দিন।

-mfpmath=sse -msse2। এটি এসএসই 2 রেজিস্টারগুলি ব্যবহার করে রাউন্ডিং সম্পাদন করে, যা প্রতিটি মধ্যবর্তী ফলাফলকে মেমোরিতে সংরক্ষণের চেয়ে অনেক দ্রুত is নোট করুন যে এটি ইতিমধ্যে x86-64 এর জন্য জিসিসিতে ডিফল্ট । থেকে জিসিসি উইকি :

-mfpmath=sse -msse2এসএসই 2 সমর্থনকারী আরও আধুনিক x86 প্রসেসরের উপর, সংকলক বিকল্পগুলি নির্দিষ্ট করে সমস্ত ভাসা এবং ডাবল ক্রিয়াকলাপগুলি এসএসই রেজিস্টারে এবং সঠিকভাবে বৃত্তাকারে সঞ্চালিত হয় তা নিশ্চিত করে। এই বিকল্পগুলি এবিআইকে প্রভাবিত করে না এবং তাই সম্ভাব্য সংখ্যার ফলাফলের জন্য যখনই সম্ভব ব্যবহার করা উচিত।

-ffp-contract=off। তবে সঠিক ম্যাচের জন্য রাউন্ডিং নিয়ন্ত্রণ করা যথেষ্ট নয়। এফএমএ (ফিউজড মাল্টিপল-অ্যাড) নির্দেশাবলী তার অ-ফিউজড অংশগুলির তুলনায় গোলাকার আচরণ পরিবর্তন করতে পারে, সুতরাং আমাদের এটি অক্ষম করতে হবে। এটি জিসিসি নয়, কলংয়ের ডিফল্ট। এই উত্তর দ্বারা ব্যাখ্যা হিসাবে :

একটি এফএমএর একটি মাত্র রাউন্ডিং থাকে (এটি কার্যকরভাবে অভ্যন্তরীণ অস্থায়ী বহুগুণ ফলাফলের জন্য অসীম নির্ভুলতা রাখে), যখন একটি এডিডি + এমএলএল দুটি থাকে।

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


1

আমি এই সমস্যায় আরও খনন করেছি এবং আরও নির্ভুলতা আনতে পারি। প্রথমত, x84_64-তে জিসিসি অনুসারে 4.45 এবং 4.55 এর সঠিক উপস্থাপনাগুলি নিম্নলিখিত (শেষ নির্ভুলতাটি মুদ্রণের জন্য লিবিউকোডমথ সহ) রয়েছে:

float 32:   4.44999980926513671875
double 64:  4.45000000000000017763568394002504646778106689453125
doublex 80: 4.449999999999999999826527652402319290558807551860809326171875
quad 128:   4.45000000000000000000000000000000015407439555097886824447823540679418548304813185723105561919510364532470703125

float 32:   4.55000019073486328125
double 64:  4.54999999999999982236431605997495353221893310546875
doublex 80: 4.550000000000000000173472347597680709441192448139190673828125
quad 128:   4.54999999999999999999999999999999984592560444902113175552176459320581451695186814276894438080489635467529296875

ম্যাক্সিম উপরে যেমন বলেছিলেন, এফপিইউ রেজিস্টারগুলির 80 বিট আকারের কারণে সমস্যা হয়।

তবে উইন্ডোজে সমস্যাটি কেন হয় না? আইএ -32-তে, x87 এফপিইউ 53 বিটের (64 বিটের মোট আকারের সমতুল্য) ম্যান্টিসার অভ্যন্তরীণ নির্ভুলতা ব্যবহারের জন্য কনফিগার করা হয়েছিল double। লিনাক্স এবং ম্যাক ওএসের জন্য, b৪ বিটের ডিফল্ট নির্ভুলতা ব্যবহার করা হয়েছিল (মোট ৮০ বিটের আকারের সমান long double:)। সুতরাং সমস্যাটি এই পৃথক প্ল্যাটফর্মগুলিতে এফপিইউর নিয়ন্ত্রণ শব্দটি পরিবর্তন করে (নির্দেশাবলীর ক্রমটি বাগটি ট্রিগার করবে) ধরে রেখে) হওয়া উচিত should সমস্যাটি জিসিসিতে বাগ 323 হিসাবে রিপোর্ট করা হয়েছে (কমপক্ষে মন্তব্য 92 টি পড়ুন!)।

উইন্ডোজটিতে ম্যান্টিসার নির্ভুলতা দেখাতে আপনি 32 টি বিটটিতে ভিসি ++ দিয়ে এটি সংকলন করতে পারেন:

#include "stdafx.h"
#include <stdio.h>  
#include <float.h>  

int main(void)
{
    char t[] = { 64, 53, 24, -1 };
    unsigned int cw = _control87(0, 0);
    printf("mantissa is %d bits\n", t[(cw >> 16) & 3]);
}

এবং লিনাক্স / সাইগউইনে:

#include <stdio.h>

int main(int argc, char **argv)
{
    char t[] = { 24, -1, 53, 64 };
    unsigned int cw = 0;
    __asm__ __volatile__ ("fnstcw %0" : "=m" (*&cw));
    printf("mantissa is %d bits\n", t[(cw >> 8) & 3]);
}

নোট করুন যে -mpc32/64/80সিসগুইনে উপেক্ষা করা হলেও সিসিভি দিয়ে আপনি এফপিইউ নির্ভুলতা সেট করতে পারেন । তবে মনে রাখবেন যে এটি ম্যান্টিসার আকার পরিবর্তন করবে, তবে ঘনিষ্ঠটি নয়, দরজাটি অন্য ধরণের বিভিন্ন আচরণের জন্য উন্মুক্ত করে দেয়।

X86_64 আর্কিটেকচারে, এসএসই ট্যান্ড্র্রি দ্বারা বলা হিসাবে ব্যবহৃত হয় , সুতরাং আপনি যদি এফপি কম্পিউটিংয়ের জন্য পুরাতন x87 এফপিইউ জোর না করে -mfpmath=387বা 32 বিট মোডে সংকলন না করে -m32(আপনার মাল্টিলেব প্যাকেজের প্রয়োজন হবে) সমস্যা না ঘটে । আমি লিনাক্সে সমস্যাটি বিভিন্ন ধরণের পতাকা এবং জিসিসির সংস্করণগুলির সংমিশ্রণে পুনরুত্পাদন করতে পারি:

g++-5 -m32 floating.cpp -O1
g++-8 -mfpmath=387 floating.cpp -O1

আমি ভিসি ++ / জিসিসি / টিসিসি দিয়ে উইন্ডোজ বা সাইগউইনে কয়েকটি সংমিশ্রণ চেষ্টা করেছি কিন্তু বাগটি কখনই প্রদর্শিত হয়নি। আমি মনে করি উত্পন্ন নির্দেশের ক্রমটি এক নয়।

পরিশেষে, দ্রষ্টব্য যে 4.45 বা 4.55 দিয়ে এই সমস্যাটি প্রতিরোধের একটি বহিরাগত উপায়টি ব্যবহার করা হবে _Decimal32/64/128তবে সমর্থনটি সত্যিই খুব কমই আছে ... কেবলমাত্র একটি মুদ্রণ করতে পেরে আমি অনেক সময় ব্যয় করেছি libdfp!


0

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

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