0 এর সমতার জন্য ভাসমান পয়েন্টের মানগুলি পরীক্ষা করা কি নিরাপদ?


100

আমি জানি আপনি সাধারণত ডাবল বা দশমিক ধরণের মানগুলির মধ্যে সমতার উপর নির্ভর করতে পারবেন না তবে আমি ভাবছি 0 যদি একটি বিশেষ ক্ষেত্রে হয়।

আমি যখন 0.00000000000000001 এবং 0.000000000000022 এর মধ্যে ছদ্মবেশগুলি বুঝতে পারি, 0 এটি নিজেই খুব খারাপ বলে মনে হচ্ছে কারণ এটি ঠিক কিছুই নয় nothing যদি আপনি কোনও কিছুর প্রতি অস্পষ্ট হন তবে এটি আর কিছুই নয়।

তবে আমি এই বিষয়টি সম্পর্কে খুব বেশি জানি না তাই এটি আমার বলার মতো নয়।

double x = 0.0;
return (x == 0.0) ? true : false;

সবসময় কি সত্য ফিরে আসবে?



5
LOL আপনি ঠিক বলেছেন। আমাকে যান
জিন রবার্টস

আমি এটি করব না কারণ আপনি জানেন না যে এক্স কীভাবে শূন্যতে সেট হয়েছে। আপনি যদি এখনও এটি করতে চান তবে আপনি সম্ভবত 1e-12 বা এর শেষে ট্যাগ হতে পারে এমনগুলি থেকে মুক্তি পেতে x বা বৃত্তাকার এক্স করতে চান।
রেক্স লোগান

উত্তর:


115

এটি আশা করা নিরাপদ যে তুলনাটি ফিরে আসবে trueএবং কেবলমাত্র যদি ডাবল ভেরিয়েবলের একটি মান থাকে 0.0(যা আপনার মূল কোড স্নিপেটে অবশ্যই আছে)। এটি ==অপারেটরের শব্দার্থবিজ্ঞানের সাথে সামঞ্জস্যপূর্ণ । a == bঅর্থ " aসমান সমান b"।

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


51

আপনার যদি অনেক "সমতা" তুলনা করার দরকার হয় তবে তুলনা করার জন্য নেট নেট in.০ এ সামান্য সহায়ক ফাংশন বা এক্সটেনশন পদ্ধতি লিখতে ভাল ধারণা হতে পারে:

public static bool AlmostEquals(this double double1, double double2, double precision)
{
    return (Math.Abs(double1 - double2) <= precision);
}

এটি নিম্নলিখিত উপায়ে ব্যবহার করা যেতে পারে:

double d1 = 10.0 * .1;
bool equals = d1.AlmostEquals(0.0, 0.0000001);

4
ডাবল 1 এবং ডাবল 2 এর সাথে তুলনা করে আপনার বিয়োগ বাতিল করার ত্রুটি হতে পারে, যদি এই সংখ্যাগুলির একে অপরের খুব কাছাকাছি মান থাকে। আমি ম্যাথটিকে অপসারণ করতাম এবং প্রতিটি শাখা স্বতন্ত্রভাবে d1> = d2 - e এবং d1 <= d2 + e পরীক্ষা
করতাম

"যেহেতু অ্যাপসিলন একটি ধনাত্মক মানের ন্যূনতম অভিব্যক্তি সংজ্ঞায়িত করেছে যার পরিসীমা শূন্যের কাছাকাছি, দুটি অনুরূপ মানের মধ্যে পার্থক্যের মার্জিনটি অবশ্যই অ্যাপসিলনের চেয়ে বেশি হওয়া উচিত। সাধারণত, এটি অ্যাপসিলনের চেয়ে বহুগুণ বেশি। এর কারণে, আমরা আপনাকে সুপারিশ করি যে আপনি এটি করবেন সমতার জন্য দ্বৈত মানগুলির তুলনা করার সময় অ্যাপসিলন ব্যবহার করবেন না। " - এমএসডিএন.মাইক্রোসফটকম /en-gb/library/ya2zha7s(v=vs.110).aspx
রাফেল কোস্টা

15

আপনার সাধারণ নমুনার জন্য, পরীক্ষাটি ঠিক আছে। তবে এ সম্পর্কে কী:

bool b = ( 10.0 * .1 - 1.0 == 0.0 );

মনে রাখবেন যে .1 বাইনারিতে পুনরাবৃত্তি দশমিক এবং ঠিক উপস্থাপন করা যায় না। তারপরে এটিকে এই কোডের সাথে তুলনা করুন:

double d1 = 10.0 * .1; // make sure the compiler hasn't optimized the .1 issue away
bool b = ( d1 - 1.0 == 0.0 );

আসল ফলাফলগুলি দেখার জন্য আমি আপনাকে একটি পরীক্ষা চালানোর জন্য ছেড়ে দেব: আপনি এটি সেভাবে মনে করার সম্ভাবনা বেশি।


5
আসলে, এটি কোনও কারণে (কমপক্ষে লিনকিউপ্যাডে) সত্য হয়।
আলেক্সি রোমানভ

আপনি ".1 ইস্যু" কী সম্পর্কে কথা বলছেন?
তেজয়

14

ডাবল.কোয়ালের জন্য এমএসডিএন এন্ট্রি থেকে :

তুলনা মধ্যে নির্ভুলতা

সমান পদ্ধতিটি সতর্কতার সাথে ব্যবহার করা উচিত, কারণ দুটি মানের ভিন্ন ভিন্ন যথার্থতার কারণে দুটি আপাত সমমানের মান অসম হতে পারে। নিম্নলিখিত উদাহরণটি জানিয়েছে যে ডাবল মান .3333 এবং 1 দ্বারা 3 কে ভাগ করে ডাবলটি অসম।

...

সাম্যের জন্য তুলনা করার পরিবর্তে, একটি প্রস্তাবিত কৌশলটিতে দুটি মানের মধ্যে একটি গ্রহণযোগ্য মার্জিন নির্ধারণ করা (যেমন মানগুলির মধ্যে একটি .01%) অন্তর্ভুক্ত। যদি দুটি মানের মধ্যে পার্থক্যটির পরম মান সেই মার্জিনের চেয়ে কম বা সমান হয়, তবে পার্থক্যটি যথাযথতার পার্থক্যের কারণে হতে পারে এবং সুতরাং, মানগুলি সমান হওয়ার সম্ভাবনা রয়েছে। নিম্নলিখিত উদাহরণটি .৩৩৩৩৩ এবং ১/৩ এর তুলনা করার জন্য এই কৌশলটি ব্যবহার করে, আগের কোড উদাহরণটি অসম হিসাবে পাওয়া যায় এমন দুটি দ্বিগুণ মান।

এছাড়াও, Double.Epsilon দেখুন


4
যথেষ্ট-সমমানের মানগুলির সমান হিসাবে তুলনা করাও এটি সম্ভব। কেউ আশা করতে পারে যে যদি x.Equals(y), তবে (1/x).Equals(1/y), তবে তা যদি xহয় 0এবং yহয় তবে তা নয় 1/Double.NegativeInfinity। এই মানগুলি সমান হিসাবে ঘোষণা করে, যদিও তাদের পারস্পরিক ক্ষতি হয় না।
সুপারক্যাট

@ সুপের্যাট: এগুলি সমান। এবং তাদের পারস্পরিক ক্ষতি নেই। আপনি আবার x = 0এবং আপনার পরীক্ষা চালাতে পারেন y = 0, এবং আপনি এখনও এটি খুঁজে পেতে চাই 1/x != 1/y
বেন ভয়েগট

@ বেনভয়েগ: টাইপ xএবং yটাইপ double? ফলাফলগুলিকে অসম প্রতিবেদন করতে আপনি কীভাবে তুলনা করবেন? নোট করুন যে 1 / 0.0 নয়এন নয়।
সুপারক্যাট

@ সুপের্যাট: ঠিক আছে, আইইইই -754 ভুল হয়ে যাওয়ার মধ্যে এটি একটি। (প্রথমত, এটি 1.0/0.0এনএএন হিসাবে হওয়া উচিত যেমনটি হওয়া উচিত, যেমন সীমাটি অনন্য নয় Second দ্বিতীয়ত, সেই অসীমতা অনন্তের ডিগ্রিগুলিতে কোনও মনোযোগ না দিয়ে একে অপরের সাথে সমান তুলনা করে)
বেন ভয়েগট

@ বেনওয়েগ্ট: যদি শূন্যটি দুটি খুব অল্প সংখ্যার গুণের ফলস্বরূপ হয়, তবে এর মধ্যে ১.০ ভাগ করে এমন মান পাওয়া উচিত যা কোনও সংখ্যার চেয়ে কম সংখ্যার তুলনায় একই চিহ্ন এবং অন্য কোনও সংখ্যার চেয়ে কম হলে ছোট সংখ্যা বিপরীত চিহ্ন ছিল। আইএমএইচও, আইইইই -754 এটির স্বাক্ষরযুক্ত শূন্য না থাকলে ভাল, তবে ইতিবাচক এবং নেতিবাচক ইনফিনিটিমাল রয়েছে।
সুপারক্যাট

6

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

float f = 0.1F;
bool b1 = (f == 0.1); //returns false
bool b2 = (f == 0.1F); //returns true

সমস্যাটি হ'ল, প্রোগ্রামার কখনও কখনও ভুলে যায় যে ইনপিলিটিড টাইপ কাস্ট (ডাবল টু ফ্লোট) তুলনার জন্য ঘটছে এবং এর ফলে এটি একটি বাগে পরিণত হয়।


3

যদি নম্বরটি সরাসরি ভাসা বা ডাবলকে নির্ধারিত করা হয় তবে শূন্য বা কোনও পুরো সংখ্যার বিরুদ্ধে পরীক্ষা করা নিরাপদ যা কোনও ফ্লোটের জন্য ডাবল বা 24 বিটের জন্য 53 বিটগুলিতে প্রতিনিধিত্ব করা যেতে পারে।

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

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


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

2

না, এটা ঠিক নেই। তথাকথিত ডেনোরমালাইজড মান (সাবমনরমাল), যখন ০.০ এর সমান হয়, মিথ্যা (শূন্য নয়) হিসাবে তুলনা করা হবে, তবে সমীকরণে ব্যবহৃত হলে এটি স্বাভাবিক করা হবে (০.০ হয়ে যাবে)। সুতরাং, শূন্যের বিভাজন এড়াতে একটি প্রক্রিয়া হিসাবে এটি ব্যবহার করা নিরাপদ নয়। পরিবর্তে, 1.0 যোগ করুন এবং 1.0 এর সাথে তুলনা করুন। এটি নিশ্চিত করবে যে সমস্ত subnormals শূন্য হিসাবে বিবেচিত হবে।


Subnormals এছাড়াও হিসাবে পরিচিত হয় denormals
ম্যানুয়েল

সাবমনরমালগুলি ব্যবহার করার সময় শূন্যের সমান হয় না, যদিও তারা সঠিক অপারেশনের উপর নির্ভর করে একই ফলাফল তৈরি করতে পারে বা নাও পারে।
Wnoise

-2

এটি ব্যবহার করে দেখুন এবং আপনি দেখতে পাবেন যে == ডাবল / ফ্লোটের জন্য নির্ভরযোগ্য নয়।
double d = 0.1 + 0.2; bool b = d == 0.3;

এখানে কোওড়া থেকে উত্তর


-5

প্রকৃতপক্ষে, আমি মনে করি যে নিম্নলিখিত কোডগুলি ডাবল মানকে 0.0 এর সাথে তুলনা করা ভাল:

double x = 0.0;
return (Math.Abs(x) < double.Epsilon) ? true : false;

ভাসা জন্য একই:

float x = 0.0f;
return (Math.Abs(x) < float.Epsilon) ? true : false;

5
ডাবল থেকে ডাবল থেকে। দুইটি মানের সমান বিবেচনা করা জন্য (সাধারণত, পার্থক্য যে মার্জিন Epsilon চেয়ে অনেক বার বেশী।) "।
অ্যালিস্টার মাও

4
@ অ্যালাস্টারম্যা এটি সাম্যের জন্য যে কোনও আকারের দ্বিগুণ চেক করতে প্রযোজ্য। সমতা শূন্যের জন্য যাচাই করার জন্য ডাবল।এপসিলন ঠিক আছে।
jwg

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

4
উদাহরণস্বরূপ: (1.0 / 5.0 + 1.0 / 5.0 - 1.0 / 10.0 - 1.0 / 10.0 - 1.0 / 10.0 - 1.0 / 10.0) <ডাবল।এপসিলন == ভুয়া (এবং যথেষ্ট পরিমাণে পরিমাপের ক্ষেত্রে: 2.78E-17 বনাম 4.94E -324)
অ্যালাস্টার

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