আমি যদি অন্য ভেরিয়েবলে একটি ফ্লোট অনুলিপি করি তবে সেগুলি কি সমান হবে?


167

আমি জানি যে ==ভাসমান-পয়েন্ট ভেরিয়েবলের সমতা পরীক্ষা করতে ব্যবহার করা ভাল উপায় নয়। তবে আমি কেবল এটি জানতে চাই যে নিম্নলিখিত বিবৃতিগুলির সাথে:

float x = ...

float y = x;

assert(y == x)

যেহেতু yঅনুলিপি করা হয়েছে x, তাই দৃ the়তা কি সত্য হবে?


78
আসল কোড সহ একটি বিক্ষোভের মাধ্যমে অসমতার প্রমাণ করে এমন কাউকে আমার 50 টি অনুদান প্রদান করুন। আমি 80 বনাম 64 বিট জিনিসটি কার্য করতে দেখতে চাই। উত্পন্ন এসেম্বলার কোডের ব্যাখ্যার জন্য অন্য 50 টি প্লাস যা একটি ভেরিয়েবলটি একটি রেজিস্টারে উপস্থিত রয়েছে এবং অন্যটি নয় (বা বৈষম্যের কারণ যাই হোক না কেন, আমি এটি কম স্তরে ব্যাখ্যা করতে চাই)।
থমাস ওয়েলার

1
@ থমাস ওয়ালার এটি সম্পর্কে জিসিসি বাগ: gcc.gnu.org/bugzilla/show_bug.cgi?id=323 ; যাইহোক, আমি কেবল এটি একটি x86-64 সিস্টেমে তিরস্কার করার চেষ্টা করেছি এবং এটি এমনকি - দ্রুত-গণিতের দ্বারাও হয় না। আমার সন্দেহ হয় আপনাকে 32-বিট সিস্টেমে একটি পুরানো জিসিসি দরকার।
pjc50

5
@ পিজেসি 50: বাগ 323 পুনরুত্পাদন করতে আসলে আপনার একটি 80-বিট সিস্টেমের প্রয়োজন; এটি 80x87 এফপিইউ যা সমস্যার কারণ হয়েছিল। x86-64 এসএসই এফপিইউ ব্যবহার করে। অতিরিক্ত বিটগুলি সমস্যার কারণ হতে পারে কারণ 32 বিট ভাসায় কোনও মান ছড়িয়ে দেওয়ার সময় এগুলি গোল হয়।
এমসাল্টাররা

4
যদি এমসাল্টার্সের তত্ত্বটি সঠিক হয় (এবং আমি সন্দেহ করি এটি হয়) তবে আপনি 32-বিট ( -m32) এর জন্য সংকলন করে বা জিসিসি কে x87 এফপিইউ ( -mfpmath=387) ব্যবহার করার জন্য নির্দেশ দিয়ে তিরস্কার করতে পারেন ।
কোডি গ্রে

4
"48 বিট" কে "80 বিট" তে পরিবর্তন করুন এবং তারপরে আপনি সেখানে "পৌরাণিক" বিশেষণটি মুছে ফেলতে পারেন, @ হট। আপনার মন্তব্যের আগে অবিলম্বে এটিই আলোচনা হচ্ছিল। X87 (x86 আর্কিটেকচারের জন্য FPU) ৮০-বিট রেজিস্টার ব্যবহার করে, একটি "বর্ধিত-নির্ভুলতা" ফর্ম্যাট।
কোডি ধূসর

উত্তর:


125

assert(NaN==NaN);কেমিড্রেকো নির্দেশিত কেসটি ছাড়াও , আপনি এক্স ৮87-গণিত নিয়ে পরিস্থিতি থাকতে পারেন, যখন ৮০ বিট ফ্লোট অস্থায়ীভাবে মেমরিতে সংরক্ষণ করা হয় এবং পরে মানগুলির সাথে তুলনা করা হয় যা এখনও একটি রেজিস্টারের অভ্যন্তরে সঞ্চিত রয়েছে।

সম্ভাব্য ন্যূনতম উদাহরণ, যা gcc9.2 এর সাথে ব্যর্থ হলে এটি ব্যর্থ হয় -O2 -m32:

#include <cassert>

int main(int argc, char**){
    float x = 1.f/(argc+2);
    volatile float y = x;
    assert(x==y);
}

গডবোল্ট ডেমো: https://godbolt.org/z/X-Xt4R

volatileসম্ভবত বাদ দেওয়া যেতে পারে যদি আপনি যথেষ্ট রেজিস্টার চাপ তৈরি করতে পরিচালনা আছে yসংরক্ষিত হয় এবং স্মৃতি থেকে পুনরায় লোড (কিন্তু কম্পাইলার যথেষ্ট, তুলনা বাদ না সব একসঙ্গে গুলান)।

জিসিসি এফএকিউ রেফারেন্স দেখুন:


2
এটি আশ্চর্যজনক বলে মনে হয় যে অতিরিক্ত বিটগুলি floatস্ট্যান্ডার্ড নির্ভুলতার সাথে অতিরিক্ত নির্ভুলতার সাথে তুলনা করার জন্য বিবেচিত হবে ।
নাট

13
@Nat এটা হয় অদ্ভুত; এটি একটি বাগ
অরবিটে হালকা ঘোড়দৌড়

13
@ থমাস ওয়েলার নো, এটি একটি যুক্তিসঙ্গত পুরষ্কার। যদিও আমি এই উত্তরটি উল্লেখ করতে চাইব যে এটি অনুপযুক্ত আচরণ নয়
লাইটনেস রেস অরবিট

4
আমি এই উত্তরটি প্রসারিত করতে পারি, সমাবেশ কোডটিতে ঠিক কী ঘটে তা নির্দেশ করে এবং এটি আসলে মানটিকে লঙ্ঘন করে - যদিও আমি নিজেকে ভাষা-আইনজীবী বলব না, তাই আমি গ্যারান্টি দিতে পারি না যে কোনও অস্পষ্টতা নেই যে ধারাটি স্পষ্টভাবে সেই আচরণের অনুমতি দেয়। আমি ধরে নিই যে ওপি প্রকৃত সংকলকগুলিতে ব্যবহারিক জটিলতায় বেশি আগ্রহী, সম্পূর্ণরূপে বাগ-মুক্ত, পুরোপুরি কমপ্লায়েন্ট কম্পাইলারগুলিতে (যা ডি-ফ্যাক্টোটি বিদ্যমান নেই, আমার ধারণা)।
chtz

4
উল্লেখযোগ্য যে উল্লেখ -ffloat-storeকরা এটিকে প্রতিরোধের উপায় বলে মনে হয়।
অরেঞ্জডোগ

116

এটি যদি xহয় তবে তা সত্য হবে না NaNকারণ যে তুলনাগুলি সর্বদা মিথ্যা (হ্যাঁ, এমনকি ) NaNare অন্যান্য সমস্ত ক্ষেত্রে (স্বাভাবিক মান, অস্বাভাবিক মান, ইনফিনিটিস, জিরো) এই দাবীটি সত্য হবে।NaN == NaN

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


যদি মান অনুসরণ করা হয় তবে প্রসারিত-নির্ভুল মূল্যায়নটি একটি নন-ইস্যু হওয়া উচিত। <cfloat>সি থেকে উত্তরাধিকার সূত্রে [5.2.4.2.2.8] ( জোর দেওয়া খনি ):

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

যাইহোক, মন্তব্যগুলি ইঙ্গিত করেছে যে, কিছু সংকলক, বিল্ড-বিকল্পগুলি এবং লক্ষ্যগুলি সহ কয়েকটি ক্ষেত্রে এটিকে বিপরীতমুখীভাবে মিথ্যা করতে পারে


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

5
x+pow(b,2)==x+pow(a,3)এর থেকে পৃথক auto one=x+pow(b,2); auto two=y+pow(a,3); one==twoহতে পারে কারণ একজনের তুলনায় অন্যের চেয়ে বেশি নির্ভুলতা ব্যবহারের তুলনা করা যেতে পারে (যদি এক / দুটি রামের 64 বিট মান হয়, তবে মধ্যবর্তী মানগুলি fpu এ 80ish বিট হয়)। সুতরাং অ্যাসাইনমেন্ট কখনও কখনও কিছু করতে পারে।
ইয়াক্ক - অ্যাডাম নেভ্রামুমন্ট

22
@ আইভিজি শিওর! আমার উত্তরটি সহজভাবে মান অনুসরণ করে। আপনি যদি আপনার সংকলকটি অ-বিভ্রান্তিকর হতে বলেন, বিশেষত দ্রুত গণিত সক্ষম করার সময় সমস্ত বেট বন্ধ রয়েছে।
kmdreko

11
@ ভু আমার উত্তরটি উদ্ধৃতি দেখুন। আরএইচএসের মান এলএইচএসে পরিবর্তনশীলকে বরাদ্দ করা হয়। এলএইচএসের ফলাফলের মানটি আরএইচএসের মান থেকে পৃথক হওয়ার কোনও আইনী সমর্থনযোগ্যতা নেই। আমি প্রশংসা করি যে বেশ কয়েকটি সংকলক এই ক্ষেত্রে বাগ আছে। তবে কোনও রেজিস্টারে কোনও কিছু সঞ্চিত আছে কিনা এর সাথে কিছু করার নেই বলে মনে করা হচ্ছে।
অরবিটে লাইটনেস রেস

6
@ ভু: আইএসও সি ++ তে, টাইপ প্রস্থের বৃত্তাকারটি কোনও অ্যাসাইনমেন্টে ঘটবে বলে মনে করা হচ্ছে। X87 লক্ষ্য করে এমন বেশিরভাগ সংকলকগুলিতে, কেবলমাত্র তখন ঘটে যখন সংকলক স্পিল / পুনরায় লোড করার সিদ্ধান্ত নেয়। আপনি gcc -ffloat-storeকঠোর সম্মতি জন্য এটি জোর করতে পারেন । তবে এই প্রশ্নটি হ'ল x=y; x==y; উভয়র মধ্যে ভিন্ন ভিন্ন কিছু না করেই। যদি yইতিমধ্যে একটি ফ্লোটে ফিট করার জন্য গোল করা হয় তবে ডাবল বা লম্বা ডাবল এবং পিছনে রূপান্তর করা মান পরিবর্তন করবে না। ...
পিটার কর্ডেস

34

হ্যাঁ, yঅবশ্যই এর মান গ্রহণ করবে x:

[expr.ass]/2: সাধারণ অ্যাসাইনমেন্টে (=), বাম অপারেন্ড দ্বারা উল্লিখিত বস্তুটির ডান অপারেন্ডের ফলাফলের সাথে এর মানটি প্রতিস্থাপন করে ([Defns.access]) পরিবর্তন করা হয়।

অন্যান্য মান নির্ধারণের জন্য কোনও ছাড় নেই।

(অন্যরা ইতিমধ্যে ইঙ্গিত করেছে যে সমতুল্য তুলনা ==যাইহোক falseএনএএন মানগুলির জন্য মূল্যায়ন করবে ।)

ভাসমান-পয়েন্ট সহ সাধারণ সমস্যাটি ==হ'ল আপনার মনে হয় যে যথেষ্ট মূল্য রয়েছে তা না পাওয়া সহজ । এখানে, আমরা জানি যে দুটি মান, তারা যাই হোক না কেন, একই রকম।


7
@ থমাস ওয়েলারের ফলস্বরূপ অ-অনুপযুক্ত বাস্তবায়নের ক্ষেত্রে এটি একটি ত্রুটিযুক্ত বাগ। যদিও এটি উল্লেখ করা ভাল!
অরবিটে লাইটনেস রেস

প্রথমদিকে, আমি ভেবেছিলাম যে "মান" এবং "ফলাফল" এর মধ্যে পার্থক্যকে আইনী করে তোলা বিভ্রান্ত হবে, তবে এই পার্থক্যটি C2.2, 7.1.6 এর ভাষা দ্বারা পৃথক হওয়া প্রয়োজন হবে না; সি 3.3, 7.1.6; C4.2, 7.1.6, বা C5.3, 7.1.6 খসড়া মানকটি আপনি উদ্ধৃত করেছেন।
এরিক টাওয়ার

@ এরিক টাওয়ারস দুঃখিত আপনি কি এই উল্লেখগুলি স্পষ্ট করে বলতে পারেন? আপনি যে দিকে ইঙ্গিত করছেন তা আমি খুঁজে পাচ্ছি না
অরবিট-এ লাইটনেস রেস

@ লাইটনেসেসেসবিওয়াই-এসএ ৩.০: সিC2.2 , C3.3 , C4.2 এবং C5.3
এরিক টাওয়ার

@ এরিক টাওয়ার হ্যাঁ, এখনও আপনাকে অনুসরণ করছে না। আপনার প্রথম লিঙ্কটি পরিশিষ্ট সি সূচীতে যায় (আমাকে কিছু বলেন না)। আপনার পরবর্তী চারটি লিঙ্কে যান [expr]। যদি আমি লিঙ্কগুলি উপেক্ষা করে উদ্ধৃতিগুলিতে মনোযোগ দিতে চাই তবে আমি এই বিভ্রান্তির সাথেই রয়ে গেছি যে উদাহরণস্বরূপ C.5.3 "মান" বা "ফলাফল" শব্দটি ব্যবহার করার বিষয়টি বোঝায় না (যদিও এটি করে এর স্বাভাবিক ইংরেজি প্রসঙ্গে একবার "ফলাফল" ব্যবহার করুন)। সম্ভবত আপনি আরও স্পষ্টভাবে বর্ণনা করতে পারেন যেখানে আপনি মনে করেন যে মানটি একটি পার্থক্য তৈরি করে এবং এই ঘটনার জন্য একটি স্পষ্ট উদ্ধৃতি প্রদান করবে provide ধন্যবাদ!
কক্ষপথে হালকাতা রেস

3

হ্যাঁ, সমস্ত ক্ষেত্রে (NaNs এবং x87 ইস্যু উপেক্ষা করা), এটি সত্য হবে।

আপনি যদি memcmpএগুলি ব্যবহার করেন তবে আপনি NaN এবং sNaN তুলনা করতে সক্ষম হয়ে সমতার জন্য পরীক্ষা করতে সক্ষম হবেন। এটির জন্য চলকটির ঠিকানা নিতেও সংকলকটির প্রয়োজন হবে যা floatএকটি 80-বিটের পরিবর্তে 32-বিটের মানকে বাধ্য করবে । এটি x87 সমস্যাগুলি দূর করবে। এখানে দ্বিতীয় দাবী ==NaNs কে সত্য হিসাবে তুলনা করবে না তা দেখাতে ব্যর্থ হওয়ার উদ্দেশ্য :

#include <cmath>
#include <cassert>
#include <cstring>

int main(void)
{
    float x = std::nan("");
    float y = x;
    assert(!std::memcmp(&y, &x, sizeof(float)));
    assert(y == x);
    return 0;
}

মনে রাখবেন যে যদি NaN এর আলাদা অভ্যন্তরীণ উপস্থাপনা থাকে (যেমন ম্যান্টিসার পরিবর্তিত হয়) তবে memcmpসত্যটি তুলনা করবে না।


1

সাধারণ ক্ষেত্রে, এটি সত্য বলে মূল্যায়ন করবে। (বা দৃ statement় বিবৃতি কিছুই করবে না)

সম্পাদনা করুন :

'সাধারণ ক্ষেত্রে' দ্বারা আমি বোঝাতে চাইছি অন্যান্য ব্যবহারকারীদের দ্বারা নির্দেশিত হিসাবে উল্লিখিত পরিস্থিতিতে (যেমন NaN মান এবং 80x87 ভাসমান পয়েন্ট ইউনিট) বাদ দিচ্ছি।

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

(8087 সম্পর্কিত রেফারেন্স - https://home.deec.uc.pt/~jlobo/tc/artofasm/ch14/ch143.htm )

একটি ভাল উদাহরণ পুনরুত্পাদন করার জন্য @ chtz টু কুডোস এবং NaNs উল্লেখ করার জন্য @kmdreko - তাদের সম্পর্কে আগে জানতেন না!


1
আমি ভেবেছিলাম স্মৃতি থেকে লোড হওয়ার xসময় কোনও ভাসমান পয়েন্ট রেজিস্ট্রারে থাকা পুরোপুরি সম্ভব ছিল y। মেমোরিতে কোনও নিবন্ধকের চেয়ে কম নির্ভুলতা থাকতে পারে, যার ফলে তুলনা ব্যর্থ হয়।
ডেভিড শোয়ার্জ

1
এটি একটি মিথ্যা ক্ষেত্রে একটি মামলা হতে পারে, আমি এতদিন ভাবিনি। (যেহেতু ওপি কোনও বিশেষ মামলা দেয় নি, তাই আমি কোনও অতিরিক্ত
বাধাও

1
আপনি কি বলছেন তা আমি সত্যিই বুঝতে পারি না। আমি যেমন প্রশ্নটি বুঝতে পারি, ওপি জিজ্ঞাসা করছে যে কোনও ফ্লোট অনুলিপি করে এবং তারপরে সাম্যের জন্য পরীক্ষা সফল হওয়ার গ্যারান্টিযুক্ত কিনা। আপনার উত্তরটি "হ্যাঁ" বলছে বলে মনে হচ্ছে। আমি জিজ্ঞাসা করছি কেন উত্তরটি না হয়।
ডেভিড শোয়ার্জ

6
সম্পাদনা এই উত্তরটি ভুল করে। সি ++ স্ট্যান্ডার্ডের প্রয়োজন হয় যে অ্যাসাইনমেন্টটি মানটিকে গন্তব্যের ধরণে রূপান্তর করে — অতিরিক্ত নির্ভুলতা এক্সপ্রেশন মূল্যায়নে ব্যবহৃত হতে পারে তবে অ্যাসাইনমেন্টের মাধ্যমে ধরে রাখা যায় না। মানটি কোনও রেজিস্টার বা স্মৃতিতে রাখা হয় কিনা তা নিরপেক্ষ; কোডটি যেমন লেখা থাকে তেমন সি ++ স্ট্যান্ডার্ডের প্রয়োজন, floatঅতিরিক্ত নির্ভুলতা ছাড়াই একটি মান।
এরিক পোস্টপিসিল

2
@ এপ্রোগ্রামার প্রদত্ত যে একটি (এন অত্যন্ত) বগি সংকলক তাত্ত্বিকভাবে একটি দৃ throw়তা উত্সাহিত করতে পারে int a=1; int b=a; assert( a==b );, আমি মনে করি সঠিকভাবে-কার্যকরী সংকলক সম্পর্কিত এই প্রশ্নের উত্তর দেওয়া কেবলমাত্র বোধগম্য (যখন সম্ভবত কিছু সংকলকের কিছু সংস্করণ আছে / আছে তা লক্ষ্য করা যায়) এই ভুল পেতে-বেন-জ্ঞাত)। ব্যবহারিক ভাষায়, যদি কোনও কারণে কোনও সংকলক কোনও রেজিস্টার-সঞ্চিত অ্যাসাইনমেন্টের ফলাফল থেকে অতিরিক্ত নির্ভুলতা অপসারণ না করে, এটির মানটি ব্যবহার করার আগে এটি করা উচিত ।
ট্রিপহাউন্ড

-1

হ্যাঁ, এটা ফিরে আসবে সত্য সবসময়, যদি এর ব্যতীত NaN । পরিবর্তনশীল মান যদি NaN হয় তবে এটি সর্বদা মিথ্যা ফেরত দেয় !

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