ভাসা এবং দ্বৈত তুলনার সবচেয়ে কার্যকর উপায় কী?


524

দুটি doubleবা দুটি floatমানের তুলনা করার সবচেয়ে কার্যকর উপায় কী হবে ?

কেবল এটি করা সঠিক নয়:

bool CompareDoubles1 (double A, double B)
{
   return A == B;
}

তবে এর মতো কিছু:

bool CompareDoubles2 (double A, double B) 
{
   diff = A - B;
   return (diff < EPSILON) && (-diff < EPSILON);
}

প্রক্রিয়াকরণ অপচয় করা বলে মনে হচ্ছে।

কেউ কি স্মার্ট ফ্লোট তুলনামূলক জানেন?


2
> ফাংশনের শুরুতে এটি যুক্ত করা আরও দক্ষ হবে? <invoke Knuth>অকালীন অপটিমাইজেশন হ'ল সমস্ত অশুভের মূল। </invoke Knuth>উপরে যেমন উল্লিখিত হয়েছে কেবল এবস (অ্যাবি) <ইপিএস সহ যান, এটি স্পষ্ট এবং সহজে বোঝা যায়।
অ্যান্ড্রু কোলসন

2
এটি বুস্ট টেস্ট লাইব্রেরিতে
কার্যকরভাবে

2
মূল পোস্টারের বাস্তবায়ন সম্পর্কে অবাস্তব একমাত্র বিষয় হ'ল এটিতে&& এ একটি অতিরিক্ত শাখা রয়েছে। ওজির উত্তরটি সর্বোত্তম। ফ্যাবস একটি আন্তঃব্যক্তিক যা এক্স ৮87 এর একটি একক নির্দেশনা, এবং আমি মনে করি যে প্রায় অন্য কোনও কিছুতে। ইতিমধ্যে ওজে এর উত্তর গ্রহণ করুন!

3
যদি আপনি পারেন তবে ভাসমান পয়েন্টটি ফেলে দিন এবং নির্দিষ্ট পয়েন্টগুলি ব্যবহার করুন। উদাহরণস্বরূপ, {ফ্লোটিং পয়েন্ট} মিটারের পরিবর্তে {ফিক্সড পয়েন্ট} মিলিমিটার ব্যবহার করুন।
টমাস ম্যাথিউজ

33
"কেবল এটি করা সঠিক নয়" - এটি নিছক আবর্জনা, অবশ্যই ব্যবহার ==করা পুরোপুরি সঠিক হতে পারে, তবে এটি পুরোপুরি প্রশ্নের মধ্যে দেওয়া প্রসঙ্গে নির্ভর করে। যতক্ষণ না যে প্রেক্ষাপটে পরিচিত, ==এখনো থাকে "সবচেয়ে কার্যকর উপায়"
খ্রিস্টান রাউ

উত্তর:


459

অন্যান্য যে কোনও পরামর্শ ব্যবহার করে অত্যন্ত সতর্কতা অবলম্বন করুন। এটি সব প্রসঙ্গে নির্ভর করে।

আমি এমন একটি সিস্টেমে বাগ সনাক্ত করতে দীর্ঘ সময় ব্যয় করেছি যা যদি ধরে নেওয়া হয় a==bযে |a-b|<epsilon। অন্তর্নিহিত সমস্যাগুলি হ'ল:

  1. একটি অ্যালগরিদমে অন্তর্নিহিত অনুমান যে যদি a==bএবং b==cতারপর a==c

  2. ইঞ্চি পরিমাপিত লাইনের জন্য মিলগুলি (.001 ইঞ্চি) মাপার জন্য একই এপসিলন ব্যবহার করে। তা a==bকিন্তু 1000a!=1000b। (এ কারণেই অলমোস্টএকুয়াল 2 এস কমপ্লেন্টস অ্যাপসিলন বা সর্বোচ্চ ইউএলপিএসের জন্য জিজ্ঞাসা করে)।

  3. উভয় কোণ এবং লাইনের দৈর্ঘ্য উভয়ের জন্য একই অ্যাপসিলনের ব্যবহার!

  4. সংগ্রহে আইটেমগুলি বাছাই করতে এ জাতীয় তুলনা ফাংশন ব্যবহার করা। (এক্ষেত্রে বিল্টিন সি ++ অপারেটর ব্যবহার করে == উত্পাদিত ডাবলস সঠিক ফলাফলের জন্য))

আমি ভালো লেগেছে বললঃ এটা সব প্রসঙ্গ এবং প্রত্যাশিত আকারের উপর নির্ভর করে aএবং b

BTW, std::numeric_limits<double>::epsilon() হ'ল "মেশিন অ্যাপসিলন"। এটি 1.0 এবং পরবর্তী মানটির মধ্যে দ্বিগুণ দ্বারা প্রতিনিধিত্বযোগ্য the আমি অনুমান করি যে এটি তুলনা ফাংশনে ব্যবহৃত হতে পারে তবে কেবলমাত্র প্রত্যাশিত মানগুলি 1 এর চেয়ে কম হলে (এটি @ সিডভির উত্তরের প্রতিক্রিয়াতে ...)

এছাড়াও, আপনার যদি মূলত intগাণিতিক থাকে তবে doubles(এখানে আমরা নির্দিষ্ট ক্ষেত্রে ইনট মানগুলি রাখতে ডাবল ব্যবহার করি) আপনার গাণিতিকটি সঠিক হবে। উদাহরণস্বরূপ ৪.০ / ২.০ 1.0 + 1.0 এর সমান হবে। আপনি যতক্ষণ না ভগ্নাংশের ফলস্বরূপ এমন কিছু না করেন (4.0 / 3.0) বা কোনও int এর আকারের বাইরে যান না এটি ততক্ষণ।


10
সুস্পষ্টভাবে নির্দেশ করার জন্য +1 (এটি প্রায়শই উপেক্ষা করা হয়)। জেনেরিক পদ্ধতির জন্য, আপনি অ্যাপসিলনটিকে তুলনামূলকভাবে তুলতে পারেন fabs(a)+fabs(b)তবে NaN, 0 যোগফল এবং ওভারফ্লো ক্ষতিপূরণ সহ, এটি বেশ জটিল হয়ে ওঠে ।
পিটারচেন

4
এমন কিছু আছে যা আমি বুঝতে পারি না। টিপিক্যাল float/ doubleহয় অংশক এক্স 2 ^ EXPepsilonউদ্দীপক উপর নির্ভরশীল হবে। উদাহরণস্বরূপ, যদি অংশক 24bits এবং এক্সপোনেন্ট 8bit সাইন করা হয়েছে, তারপর 1/(2^24)*2^127বা ~2^103একটি হল epsilonকিছু মান জন্য; বা এটি একটি সর্বনিম্ন অ্যাপসিলনের কথা উল্লেখ করছে ?
নির্মম আওয়াজ

3
এক সেকেন্ড অপেক্ষা কর. আমি যা বলতে চেয়েছি তা কি? আপনি কেন বলছেন |a-b|<epsilon, সঠিক নয় । আপনার উত্তরে এই লিঙ্কটি যুক্ত করুন; আপনি যদি সাইগনাস- সফ্টওয়্যার.কম / পেপারস / কম্পারিংফ্লোটস / কম্পেরিংফ্লোটস htm এর সাথে সম্মত হন এবং আমি আমার বোবা মন্তব্যগুলি সরাতে পারি।
নির্মম আওয়াজ

3
এটি একটি দীর্ঘ মন্তব্য, নিজের মধ্যে কোনও উত্তর নয়। সমস্ত প্রসঙ্গে কি আছে (সেট) প্রমিত উত্তর (গুলি)?
মের্লিন মরগান-গ্রাহাম

2
পুরানো লিঙ্কটি অপ্রচলিত বলে মনে হচ্ছে, নতুন পৃষ্ঠাটি এখানে র্যান্ডোমাসিআই.ওয়ার্ডপ্রেস.কম
মাও

174

বেশিরভাগ লোকেরা (এমনকি গেম প্রোগ্রামিংয়েও) এপিলন মানের সাথে তুলনা করা The

আপনার বাস্তবায়নটি সামান্য হলেও পরিবর্তন করা উচিত:

bool AreSame(double a, double b)
{
    return fabs(a - b) < EPSILON;
}

সম্পাদনা: সাম্প্রতিক ব্লগ পোস্টে ক্রিস্টার এই বিষয়ে দুর্দান্ত তথ্য একটি স্ট্যাক যুক্ত করেছেন । উপভোগ করুন।


@ ওজে: প্রথম কোডের নমুনায় কিছু ভুল আছে? আমি ভেবেছিলাম একমাত্র সমস্যাটি এইরকম পরিস্থিতিতে ছিল: float a = 3.4; if(a == 3.4){...}অর্থাত্ যখন আপনি কোনও আক্ষরিক সাথে কোনও সঞ্চিত ভাসমান বিন্দুর তুলনা করছেন | এই ক্ষেত্রে, উভয় সংখ্যা সংরক্ষণ করা হয়, সুতরাং তাদের সমান উপস্থাপনা থাকবে, যদি সমান হয়, তবে এতে ক্ষতি কি a == b?
লেজার

11
@ দনরেবা: কেবলমাত্র EPSILONহিসাবে সংজ্ঞায়িত হলে DBL_EPSILON। সাধারণত এটি তুলনার প্রয়োজনীয় নির্ভুলতার উপর নির্ভর করে বেছে নেওয়া একটি নির্দিষ্ট মান হবে।
নিমো 157

7
EPSILONযখন ভাসমানগুলি বড় হয় তখন তুলনা কাজ করে না, কারণ ধারাবাহিক ফ্লোটের মধ্যে পার্থক্যও বড় হয়। এই নিবন্ধটি দেখুন ।
কেভিনটোডিসকো

22
আশ্চর্যের কিছু নেই কিছু খেলায় জেড-যুদ্ধ যখন অঙ্গবিন্যাস / দূরে দপদপ করে ওঠার বস্তু, যুদ্ধক্ষেত্রের 4. মত পার্থক্য সঙ্গে তুলনা হয় EPSILONপ্রায় কাছাকাছি অনর্থক। হাতের ইউনিটগুলির জন্য আপনাকে একটি প্রান্তিকের সাথে তুলনা করা দরকার। এছাড়াও, std::absযেহেতু এটি বিভিন্ন ভাসমান পয়েন্টের ধরণের জন্য ওভারলোড হয় তাই ব্যবহার করুন।
ম্যাক্সিম এগারুশকিন

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

115

আমি দেখতে পেলাম যে গুগল সি ++ টেস্টিং ফ্রেমওয়ার্কে অলোস্টেমুয়াল 2 এস কমপ্লিমেন্টের একটি দুর্দান্ত ক্রস-প্ল্যাটফর্ম টেম্পলেট ভিত্তিক প্রয়োগ রয়েছে যা দ্বৈত এবং ভাসমান উভয় ক্ষেত্রেই কাজ করে। প্রদত্ত যে বিএসডি লাইসেন্সের আওতায় মুক্তি পেয়েছে, আপনার নিজের কোডটিতে এটি ব্যবহার করা কোনও সমস্যা হবে না, যতক্ষণ আপনি লাইসেন্সটি ধরে রাখেন। আমি নীচের কোডটি http://code.google.com/p/googletest/source/browse/trunk/incolve/gtest/intern/gtest-internal.h https://github.com/google/googletest/blob থেকে বের করেছি / মাস্টার / গুগলস্ট / ইনক্লিনড / গেস্ট / ইনটার্নাল / গেটেস্ট- ইনটার্নাল এইচ এবং লাইসেন্স যুক্ত করে শীর্ষে।

GTEST_OS_WINDOWS কে কিছু মান (বা আপনার কোডবেসের সাথে মানানসই কোডটি পরিবর্তন করার জন্য কোডটি পরিবর্তন করতে - এটি সর্বোপরি BSD লাইসেন্স পেয়েছে) নিশ্চিত করতে ভুলবেন না।

ব্যবহারের উদাহরণ:

double left  = // something
double right = // something
const FloatingPoint<double> lhs(left), rhs(right);

if (lhs.AlmostEquals(rhs)) {
  //they're equal!
}

কোডটি এখানে:

// Copyright 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee)
//
// The Google C++ Testing Framework (Google Test)


// This template class serves as a compile-time function from size to
// type.  It maps a size in bytes to a primitive type with that
// size. e.g.
//
//   TypeWithSize<4>::UInt
//
// is typedef-ed to be unsigned int (unsigned integer made up of 4
// bytes).
//
// Such functionality should belong to STL, but I cannot find it
// there.
//
// Google Test uses this class in the implementation of floating-point
// comparison.
//
// For now it only handles UInt (unsigned int) as that's all Google Test
// needs.  Other types can be easily added in the future if need
// arises.
template <size_t size>
class TypeWithSize {
 public:
  // This prevents the user from using TypeWithSize<N> with incorrect
  // values of N.
  typedef void UInt;
};

// The specialization for size 4.
template <>
class TypeWithSize<4> {
 public:
  // unsigned int has size 4 in both gcc and MSVC.
  //
  // As base/basictypes.h doesn't compile on Windows, we cannot use
  // uint32, uint64, and etc here.
  typedef int Int;
  typedef unsigned int UInt;
};

// The specialization for size 8.
template <>
class TypeWithSize<8> {
 public:
#if GTEST_OS_WINDOWS
  typedef __int64 Int;
  typedef unsigned __int64 UInt;
#else
  typedef long long Int;  // NOLINT
  typedef unsigned long long UInt;  // NOLINT
#endif  // GTEST_OS_WINDOWS
};


// This template class represents an IEEE floating-point number
// (either single-precision or double-precision, depending on the
// template parameters).
//
// The purpose of this class is to do more sophisticated number
// comparison.  (Due to round-off error, etc, it's very unlikely that
// two floating-points will be equal exactly.  Hence a naive
// comparison by the == operation often doesn't work.)
//
// Format of IEEE floating-point:
//
//   The most-significant bit being the leftmost, an IEEE
//   floating-point looks like
//
//     sign_bit exponent_bits fraction_bits
//
//   Here, sign_bit is a single bit that designates the sign of the
//   number.
//
//   For float, there are 8 exponent bits and 23 fraction bits.
//
//   For double, there are 11 exponent bits and 52 fraction bits.
//
//   More details can be found at
//   http://en.wikipedia.org/wiki/IEEE_floating-point_standard.
//
// Template parameter:
//
//   RawType: the raw floating-point type (either float or double)
template <typename RawType>
class FloatingPoint {
 public:
  // Defines the unsigned integer type that has the same size as the
  // floating point number.
  typedef typename TypeWithSize<sizeof(RawType)>::UInt Bits;

  // Constants.

  // # of bits in a number.
  static const size_t kBitCount = 8*sizeof(RawType);

  // # of fraction bits in a number.
  static const size_t kFractionBitCount =
    std::numeric_limits<RawType>::digits - 1;

  // # of exponent bits in a number.
  static const size_t kExponentBitCount = kBitCount - 1 - kFractionBitCount;

  // The mask for the sign bit.
  static const Bits kSignBitMask = static_cast<Bits>(1) << (kBitCount - 1);

  // The mask for the fraction bits.
  static const Bits kFractionBitMask =
    ~static_cast<Bits>(0) >> (kExponentBitCount + 1);

  // The mask for the exponent bits.
  static const Bits kExponentBitMask = ~(kSignBitMask | kFractionBitMask);

  // How many ULP's (Units in the Last Place) we want to tolerate when
  // comparing two numbers.  The larger the value, the more error we
  // allow.  A 0 value means that two numbers must be exactly the same
  // to be considered equal.
  //
  // The maximum error of a single floating-point operation is 0.5
  // units in the last place.  On Intel CPU's, all floating-point
  // calculations are done with 80-bit precision, while double has 64
  // bits.  Therefore, 4 should be enough for ordinary use.
  //
  // See the following article for more details on ULP:
  // http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm.
  static const size_t kMaxUlps = 4;

  // Constructs a FloatingPoint from a raw floating-point number.
  //
  // On an Intel CPU, passing a non-normalized NAN (Not a Number)
  // around may change its bits, although the new value is guaranteed
  // to be also a NAN.  Therefore, don't expect this constructor to
  // preserve the bits in x when x is a NAN.
  explicit FloatingPoint(const RawType& x) { u_.value_ = x; }

  // Static methods

  // Reinterprets a bit pattern as a floating-point number.
  //
  // This function is needed to test the AlmostEquals() method.
  static RawType ReinterpretBits(const Bits bits) {
    FloatingPoint fp(0);
    fp.u_.bits_ = bits;
    return fp.u_.value_;
  }

  // Returns the floating-point number that represent positive infinity.
  static RawType Infinity() {
    return ReinterpretBits(kExponentBitMask);
  }

  // Non-static methods

  // Returns the bits that represents this number.
  const Bits &bits() const { return u_.bits_; }

  // Returns the exponent bits of this number.
  Bits exponent_bits() const { return kExponentBitMask & u_.bits_; }

  // Returns the fraction bits of this number.
  Bits fraction_bits() const { return kFractionBitMask & u_.bits_; }

  // Returns the sign bit of this number.
  Bits sign_bit() const { return kSignBitMask & u_.bits_; }

  // Returns true iff this is NAN (not a number).
  bool is_nan() const {
    // It's a NAN if the exponent bits are all ones and the fraction
    // bits are not entirely zeros.
    return (exponent_bits() == kExponentBitMask) && (fraction_bits() != 0);
  }

  // Returns true iff this number is at most kMaxUlps ULP's away from
  // rhs.  In particular, this function:
  //
  //   - returns false if either number is (or both are) NAN.
  //   - treats really large numbers as almost equal to infinity.
  //   - thinks +0.0 and -0.0 are 0 DLP's apart.
  bool AlmostEquals(const FloatingPoint& rhs) const {
    // The IEEE standard says that any comparison operation involving
    // a NAN must return false.
    if (is_nan() || rhs.is_nan()) return false;

    return DistanceBetweenSignAndMagnitudeNumbers(u_.bits_, rhs.u_.bits_)
        <= kMaxUlps;
  }

 private:
  // The data type used to store the actual floating-point number.
  union FloatingPointUnion {
    RawType value_;  // The raw floating-point number.
    Bits bits_;      // The bits that represent the number.
  };

  // Converts an integer from the sign-and-magnitude representation to
  // the biased representation.  More precisely, let N be 2 to the
  // power of (kBitCount - 1), an integer x is represented by the
  // unsigned number x + N.
  //
  // For instance,
  //
  //   -N + 1 (the most negative number representable using
  //          sign-and-magnitude) is represented by 1;
  //   0      is represented by N; and
  //   N - 1  (the biggest number representable using
  //          sign-and-magnitude) is represented by 2N - 1.
  //
  // Read http://en.wikipedia.org/wiki/Signed_number_representations
  // for more details on signed number representations.
  static Bits SignAndMagnitudeToBiased(const Bits &sam) {
    if (kSignBitMask & sam) {
      // sam represents a negative number.
      return ~sam + 1;
    } else {
      // sam represents a positive number.
      return kSignBitMask | sam;
    }
  }

  // Given two numbers in the sign-and-magnitude representation,
  // returns the distance between them as an unsigned number.
  static Bits DistanceBetweenSignAndMagnitudeNumbers(const Bits &sam1,
                                                     const Bits &sam2) {
    const Bits biased1 = SignAndMagnitudeToBiased(sam1);
    const Bits biased2 = SignAndMagnitudeToBiased(sam2);
    return (biased1 >= biased2) ? (biased1 - biased2) : (biased2 - biased1);
  }

  FloatingPointUnion u_;
};

সম্পাদনা: এই পোস্টটির বয়স 4 বছর। এটি সম্ভবত এখনও বৈধ, এবং কোডটি দুর্দান্ত, তবে কিছু লোক উন্নতি পেয়েছে। সেরা AlmostEqualsগুগল টেস্ট উত্স কোড থেকে ডান এর সর্বশেষতম সংস্করণ পান, এবং আমি এখানে আটকানো একটি নয়।


3
+1: আমি সম্মত করি এটি সঠিক is তবে এটি কেন তা ব্যাখ্যা করে না। এখানে দেখুন: cygnus-software.com/papers/comperingfloats/comperingfloats.htm আমি শীর্ষে স্কোর সম্পর্কে আমার মন্তব্য লেখার পরে আমি এই ব্লগ পোস্টটি পড়ি; আমি বিশ্বাস করি এটি একই কথা বলে এবং উপরোক্ত বাস্তবায়নযোগ্য যুক্তি / সমাধান সরবরাহ করে। কারণ এখানে অনেক কোড রয়েছে, লোকেরা উত্তরটি মিস করবে।
নির্মম আওয়াজ

ফ্লোটপয়েন্ট <ডাবল> এফপি (0.03f) বলার মতো অন্তর্নিহিত ক্যাসেটগুলি যখন ঘটে তখন এমন দু'টি কদর্য জিনিস ঘটতে পারে। এটি রোধ করতে সহায়তা করার জন্য আমি এটিতে কয়েকটি পরিবর্তন করেছি। টেমপ্লেট <টাইপনেম ইউ> সুস্পষ্ট ফ্লোটিংপয়েন্ট (কনস্ট্যান্ড ইউ অ্যান্ড এক্স) {যদি (টাইপড (ইউ) .নাম ()! = টাইপড (কাঁচা টাইপ) .নাম ()) d স্টাড :: সেরার << "আপনি এতে অন্তর্নিহিত রূপান্তর করছেন ভাসমান পয়েন্ট, "<< স্টাড :: এন্ডেল" করবেন না; assert (typid (U) .name () == typid (RawType) .name ()); } u_.value_ = x; }
জেফচার্টার 21'16

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

3
নতুন কোড স্নিপেটের জন্য, এখানে এবং এখানে দেখুন
জায়েজ

1
আমি গিস্ট ফাইলে প্রয়োজনীয় লাইনগুলি বের করেছি racted যে কেউ এখান থেকে পৌঁছতে পারে ।
ইউসুফ তারেক জ্ঞানদিন

111

প্রাসঙ্গিক উপর নির্ভর করে ভাসমান পয়েন্ট সংখ্যা তুলনা। যেহেতু অপারেশনের ক্রম পরিবর্তন করাও বিভিন্ন ফলাফল আনতে পারে, তাই আপনি সংখ্যাটি কীভাবে "সমান" হতে চান তা জানা গুরুত্বপূর্ণ।

ব্রুস ডসনের দ্বারা ভাসমান পয়েন্ট সংখ্যাগুলির তুলনা ফ্লোটিং পয়েন্ট তুলনা দেখার সময় শুরু করার জন্য ভাল জায়গা।

নিম্নলিখিত সংজ্ঞাগুলি নুথের কম্পিউটার প্রোগ্রামিং আর্ট থেকে এসেছে :

bool approximatelyEqual(float a, float b, float epsilon)
{
    return fabs(a - b) <= ( (fabs(a) < fabs(b) ? fabs(b) : fabs(a)) * epsilon);
}

bool essentiallyEqual(float a, float b, float epsilon)
{
    return fabs(a - b) <= ( (fabs(a) > fabs(b) ? fabs(b) : fabs(a)) * epsilon);
}

bool definitelyGreaterThan(float a, float b, float epsilon)
{
    return (a - b) > ( (fabs(a) < fabs(b) ? fabs(b) : fabs(a)) * epsilon);
}

bool definitelyLessThan(float a, float b, float epsilon)
{
    return (b - a) > ( (fabs(a) < fabs(b) ? fabs(b) : fabs(a)) * epsilon);
}

অবশ্যই, এপসিলন নির্বাচন করা প্রসঙ্গে নির্ভর করে এবং আপনি সংখ্যাটি কতটা সমান হতে চান তা নির্ধারণ করে।

ভাসমান পয়েন্ট সংখ্যাগুলির তুলনা করার আরেকটি পদ্ধতি হ'ল সংখ্যার ইউএলপি (শেষ স্থানে থাকা ইউনিট) দেখতে হবে। বিশেষত তুলনার সাথে কথা না বলার সময়, কাগজটি প্রতিটি কম্পিউটার বিজ্ঞানী ভাসমান পয়েন্ট সংখ্যা সম্পর্কে যা জানা উচিত তা ভাসমান পয়েন্ট কীভাবে কাজ করে এবং ইউএলপি কী তা সহ কী কী ক্ষতি হয় তা বোঝার জন্য এটি একটি ভাল উত্স।


1
কোন সংখ্যাটি আরও ছোট / বড় তা নির্ধারণ করার জন্য পোস্ট করার জন্য ধন্যবাদ!
টমেটো

1
fabs(a - b) <= ( (fabs(a) < fabs(b) ? fabs(b) : fabs(a)) * epsilon);আমার বাঁচা এলওএল নোট করুন যে এই সংস্করণটি (আমি অন্যদের জন্যও প্রযোজ্য কিনা তা আমি পরীক্ষা করে দেখিনি) এছাড়াও ভাসমান পয়েন্ট সংখ্যার অবিচ্ছেদ্য অংশে যে পরিবর্তন হতে পারে তা বিবেচনা করে (উদাহরণ: 2147352577.9999997616 == 2147352576.0000000000আপনি পরিষ্কারভাবে দেখতে পারেন যে সেখানে প্রায় পার্থক্য রয়েছে 2দুটি সংখ্যার মধ্যে) যা বেশ সুন্দর! সংঘবদ্ধ বৃত্তাকার ত্রুটি সংখ্যার দশমিক অংশটি উপচে পড়লে এটি ঘটে।
rbaleksandar

ব্রুস ডসনের খুব সুন্দর এবং সহায়ক নিবন্ধ, ধন্যবাদ!
ববমোরানে

2
এই প্রশ্নটি সি ++ ট্যাগ করা হয়েছে, আপনার চেকগুলি std::max(std::abs(a), std::abs(b))(বা সহ std::min()) হিসাবে লিখিতভাবে পড়া সহজ হবে ; std::absসি ++ এ ভাসা এবং দ্বৈত প্রকারের সাথে ওভারলোড হয়, সুতরাং এটি ঠিক কাজ করে (আপনি সর্বদা fabsপাঠযোগ্যতার জন্য রাখতে পারেন )।
রাজাখেল

1
আমার কোডটিতে সমস্যাটি দেখা গেছে, আসল প্রত্যাশিত মান এবং পার্সড স্ট্রিংয়ের মধ্যে পার্থক্য রয়েছে।
mwpowellhtx

47

গভীরতার পদ্ধতির আরও তথ্যের জন্য ভাসমান পয়েন্ট সংখ্যাগুলির তুলনা পড়ুন । এই লিঙ্ক থেকে কোড স্নিপেট এখানে:

// Usable AlmostEqual function    
bool AlmostEqual2sComplement(float A, float B, int maxUlps)    
{    
    // Make sure maxUlps is non-negative and small enough that the    
    // default NAN won't compare as equal to anything.    
    assert(maxUlps > 0 && maxUlps < 4 * 1024 * 1024);    
    int aInt = *(int*)&A;    
    // Make aInt lexicographically ordered as a twos-complement int    
    if (aInt < 0)    
        aInt = 0x80000000 - aInt;    
    // Make bInt lexicographically ordered as a twos-complement int    
    int bInt = *(int*)&B;    
    if (bInt < 0)    
        bInt = 0x80000000 - bInt;    
    int intDiff = abs(aInt - bInt);    
    if (intDiff <= maxUlps)    
        return true;    
    return false;    
}

14
ম্যাক্সআপসের প্রস্তাবিত মান কী?
unj2

6
" *(int*)&A;" কঠোর আলিয়াজিং বিধি লঙ্ঘন করবে ?
osgx

3
গেইস্টের (ইউএলপি অনুসন্ধান) মতে , 4 একটি গ্রহণযোগ্য নম্বর।

4
এবং এখানে ব্রুস ডসন এর কাগজ (যা এক কাগজ এর ইন্ট্রো সংযুক্ত করা হয়) করার জন্য একটি দম্পতি আপডেট আছেন: randomascii.wordpress.com/2012/02/25/... এবং randomascii.wordpress.com/2012/06/26/...
মাইকেল Burr


27

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

আমরা ফ্লোটিং-পয়েন্ট সহনশীলতার পুনর্বিবেচনায় আরও কিছু বাস্তব নিবন্ধ খুঁজে পেতে পারি এবং নোটগুলি রয়েছে নিরঙ্কুশ সহনশীলতা পরীক্ষা যা সি ++ এ এটিকে ফুটিয়ে তোলে:

bool absoluteToleranceCompare(double x, double y)
{
    return std::fabs(x - y) <= std::numeric_limits<double>::epsilon() ;
}

এবং আপেক্ষিক সহনশীলতা পরীক্ষা:

bool relativeToleranceCompare(double x, double y)
{
    double maxXY = std::max( std::fabs(x) , std::fabs(y) ) ;
    return std::fabs(x - y) <= std::numeric_limits<double>::epsilon()*maxXY ;
}

নিবন্ধ নোট পরম পরীক্ষা ব্যর্থ হলে যে xএবং yবড় এবং আপেক্ষিক ক্ষেত্রে ব্যর্থ হলে তারা ছোট হয়। তিনি নিরঙ্কুশ এবং আপেক্ষিক সহনশীলতা হ'ল এক হিসাবে সম্মিলিত পরীক্ষাটি দেখতে এরকম হবে:

bool combinedToleranceCompare(double x, double y)
{
    double maxXYOne = std::max( { 1.0, std::fabs(x) , std::fabs(y) } ) ;

    return std::fabs(x - y) <= std::numeric_limits<double>::epsilon()*maxXYOne ;
}

25

সি ++ তে অ্যাপসিলন পাওয়ার পোর্টেবল উপায়

#include <limits>
std::numeric_limits<double>::epsilon()

তারপরে তুলনা ফাংশন হয়ে যায়

#include <cmath>
#include <limits>

bool AreSame(double a, double b) {
    return std::fabs(a - b) < std::numeric_limits<double>::epsilon();
}

34
আপনি সম্ভবত এই অ্যাপসিলনের একাধিকটি চাইবেন।
user7116

11
আপনি কি শুধু এসটিডি :: অ্যাবস ব্যবহার করতে পারবেন না? আফাইক, স্ট্যান্ড :: অ্যাবসও ডাবলসের জন্য ওভারলোড হয়েছে। আমি ভুল হলে আমাকে সতর্ক করুন।
কলিস্টিভরা

3
@ কলিসটিভ্রা, আপনি ভুল বলেছেন। 'ফাবস' এ 'চ' এর অর্থ টাইপ ফ্লোট নয়। আপনি সম্ভবত সি ফাংশন ফ্যাবসএফ () এবং ফেবসএল () এর কথা ভাবছেন।
jcoffland

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

5
আমি জানি এটি পুরানো তবে স্টাড :: এ্যাবস cmath এ ভাসমান পয়েন্ট ধরণের জন্য ওভারলোড হয়েছে।
mholzmann

18

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

দ্রুত সংক্ষিপ্তসার

  1. 1e-8 কি প্রায় 1e-16 এর মতো? আপনি যদি কোলাহল সেন্সর ডেটার দিকে তাকিয়ে থাকেন তবে সম্ভবত হ্যাঁ তবে আপনি যদি অণু সিমুলেশন করছেন তবে তা নাও হতে পারে! নীচের লাইন: আপনার সবসময় সহনশীলতার কথা ভাবা উচিত নির্দিষ্ট ফাংশন কলের প্রসঙ্গে মান সম্পর্কে এবং এটি কেবল জেনেরিক অ্যাপ-ওয়াইড হার্ড-কোডড ধ্রুবক হিসাবে তৈরি করা উচিত নয়।
  2. সাধারণ লাইব্রেরির ক্রিয়াকলাপগুলির জন্য, ডিফল্ট সহনশীলতার সাথে প্যারামিটারটি রাখা ভাল । একটি সাধারণ পছন্দnumeric_limits::epsilon() যা float.h এ FLT_EPSILON এর সমান। এটি তবে সমস্যাযুক্ত কারণ 1.0 এর মতো মানের তুলনা করার জন্য অ্যাপসিলন 1E9 এর মতো মানগুলির জন্য অ্যাপসিলনের মতো নয়। FLT_EPSILON 1.0 এর জন্য সংজ্ঞায়িত করা হয়েছে।
  3. সংখ্যাটি সহনশীলতার মধ্যে রয়েছে কিনা তা যাচাই করার সুস্পষ্ট বাস্তবায়ন fabs(a-b) <= epsilonতবে এটি কাজ করে না কারণ ডিফল্ট অ্যাপসিলনটি 1.0 এর জন্য সংজ্ঞায়িত করা হয়। আমাদের এপিলনকে a এবং b এর শর্তে উপরে বা নীচে স্কেল করতে হবে।
  4. এই সমস্যার দুটি সমাধান রয়েছে: হয় আপনি অ্যাপসিলনকে আনুপাতিকভাবে নির্ধারণ করেন max(a,b)অথবা আপনি একটি এর আশেপাশে পরবর্তী উপস্থাপনযোগ্য সংখ্যা পেতে পারেন এবং তারপরে দেখুন খটি এই সীমার মধ্যে পড়ে কিনা। প্রাক্তনটিকে "আপেক্ষিক" পদ্ধতি এবং পরে ইউএলপি পদ্ধতি বলা হয়।
  5. 0 এর সাথে তুলনা করার সময় উভয় পদ্ধতিই আসলে ব্যর্থ হয় this এই ক্ষেত্রে, অ্যাপ্লিকেশনটিকে অবশ্যই সঠিক সহনশীলতা সরবরাহ করতে হবে।

ইউটিলিটি ফাংশন বাস্তবায়ন (সি ++ 11)

//implements relative method - do not use for comparing with zero
//use this most of the time, tolerance needs to be meaningful in your context
template<typename TReal>
static bool isApproximatelyEqual(TReal a, TReal b, TReal tolerance = std::numeric_limits<TReal>::epsilon())
{
    TReal diff = std::fabs(a - b);
    if (diff <= tolerance)
        return true;

    if (diff < std::fmax(std::fabs(a), std::fabs(b)) * tolerance)
        return true;

    return false;
}

//supply tolerance that is meaningful in your context
//for example, default tolerance may not work if you are comparing double with float
template<typename TReal>
static bool isApproximatelyZero(TReal a, TReal tolerance = std::numeric_limits<TReal>::epsilon())
{
    if (std::fabs(a) <= tolerance)
        return true;
    return false;
}


//use this when you want to be on safe side
//for example, don't start rover unless signal is above 1
template<typename TReal>
static bool isDefinitelyLessThan(TReal a, TReal b, TReal tolerance = std::numeric_limits<TReal>::epsilon())
{
    TReal diff = a - b;
    if (diff < tolerance)
        return true;

    if (diff < std::fmax(std::fabs(a), std::fabs(b)) * tolerance)
        return true;

    return false;
}
template<typename TReal>
static bool isDefinitelyGreaterThan(TReal a, TReal b, TReal tolerance = std::numeric_limits<TReal>::epsilon())
{
    TReal diff = a - b;
    if (diff > tolerance)
        return true;

    if (diff > std::fmax(std::fabs(a), std::fabs(b)) * tolerance)
        return true;

    return false;
}

//implements ULP method
//use this when you are only concerned about floating point precision issue
//for example, if you want to see if a is 1.0 by checking if its within
//10 closest representable floating point numbers around 1.0.
template<typename TReal>
static bool isWithinPrecisionInterval(TReal a, TReal b, unsigned int interval_size = 1)
{
    TReal min_a = a - (a - std::nextafter(a, std::numeric_limits<TReal>::lowest())) * interval_size;
    TReal max_a = a + (std::nextafter(a, std::numeric_limits<TReal>::max()) - a) * interval_size;

    return min_a <= b && max_a >= b;
}

isDefinitelyLessThanচেকস diff < tolerance, যার অর্থ a এবং b প্রায় সমান (এবং সুতরাং একটি অবশ্যই খ এর চেয়ে কম নয়)। উভয় ক্ষেত্রে পৃথক> সহনশীলতা যাচাই করা কি আরও বেশি অর্থবোধ করে না? অথবা সম্ভবত একটি orEqualToযুক্তি যুক্ত করুন যা নিয়ন্ত্রণ করে আনুমানিক সমতা চেকটি সত্য হওয়া উচিত এবং না।
ম্যাট চেম্বারস

14

আপনার লেখা কোডটি বাগড হয়েছে:

return (diff < EPSILON) && (-diff > EPSILON);

সঠিক কোডটি হ'ল:

return (diff < EPSILON) && (diff > -EPSILON);

(... এবং হ্যাঁ এটি আলাদা)

আমি ভাবছি যদি কৌতুকগুলি আপনাকে কোনও ক্ষেত্রে অলস মূল্যায়ন হারাতে না পারে। আমি বলব এটি সংকলকের উপর নির্ভর করে। আপনি উভয় চেষ্টা করতে পারেন। এগুলি যদি গড়ের সমতুল্য হয়, তবে বাস্তবায়নটি কড়া দিয়ে নিন।

দুটি ফ্লোটের মধ্যে কোনটির চেয়ে অন্যটির চেয়ে বড় হওয়ার সম্ভাবনা সম্পর্কে আপনার কাছে যদি কিছু তথ্য থাকে তবে অলস মূল্যায়নের আরও ভাল সুবিধা নিতে আপনি তুলনার ক্রমে খেলতে পারেন।

শেষ পর্যন্ত আপনি এই ফাংশনটি অন্তর্ভুক্ত করে আরও ভাল ফলাফল পেতে পারেন। যদিও তেমন উন্নতির সম্ভাবনা নেই ...

সম্পাদনা করুন: ওজে, আপনার কোড সংশোধন করার জন্য ধন্যবাদ। আমি সেই অনুযায়ী আমার মন্তব্য মুছলাম


13

`ফিবিগুলি ফিরুন (ক - খ) <ইপিএসলন;

এটি ঠিক আছে যদি:

  • আপনার ইনপুটগুলির আকারের ক্রমটি খুব বেশি পরিবর্তন হয় না
  • খুব কম সংখ্যক বিপরীত চিহ্নকে সমান হিসাবে বিবেচনা করা যেতে পারে

তবে অন্যথায় এটি আপনাকে সমস্যায় ফেলবে। ডাবল স্পষ্টতা সংখ্যার প্রায় 16 দশমিক স্থানের রেজোলিউশন রয়েছে। আপনি যে দুটি সংখ্যার সাথে তুলনা করছেন তা যদি ইপিএসলন * ১.০ ই 16 এর চেয়ে বেশি মাত্রায় হয় তবে আপনি সম্ভবত বলছেন:

return a==b;

আমি একটি ভিন্ন পদ্ধতির পরীক্ষা করব যা ধরে নিয়েছে যে আপনাকে প্রথম ইস্যু সম্পর্কে চিন্তা করা দরকার এবং দ্বিতীয়টি আপনার আবেদনটি ঠিক আছে বলে ধরে নেওয়া উচিত। একটি সমাধান কিছু হবে:

#define VERYSMALL  (1.0E-150)
#define EPSILON    (1.0E-8)
bool AreSame(double a, double b)
{
    double absDiff = fabs(a - b);
    if (absDiff < VERYSMALL)
    {
        return true;
    }

    double maxAbs  = max(fabs(a) - fabs(b));
    return (absDiff/maxAbs) < EPSILON;
}

এটি গণনাগতভাবে ব্যয়বহুল, তবে এটি কখনও কখনও যা জন্য ডাকা হয়। আমাদের সংস্থায় এটিই আমাদের করতে হবে কারণ আমরা একটি ইঞ্জিনিয়ারিং লাইব্রেরি নিয়ে কাজ করি এবং ইনপুটগুলি কয়েক ডজন আদেশের দ্বারা পৃথক হতে পারে।

যাইহোক, মূল বিষয়টি হ'ল (এবং কার্যত প্রতিটি প্রোগ্রামিং সমস্যার ক্ষেত্রে প্রযোজ্য): আপনার প্রয়োজনীয়তাগুলি কী তা মূল্যায়ন করুন, তারপরে আপনার প্রয়োজনগুলি সমাধানের জন্য একটি সমাধান নিয়ে আসুন - সহজ উত্তরটি আপনার প্রয়োজনগুলিকে সম্বোধন করবে তা অনুমান করবেন না। যদি আপনার মূল্যায়নের পরে যদি আপনি খুঁজে পান যে fabs(a-b) < EPSILONযথেষ্ট হবে, নিখুঁত - এটি ব্যবহার করুন! তবে এর ত্রুটিগুলি এবং অন্যান্য সম্ভাব্য সমাধানগুলি সম্পর্কেও সচেতন হন।


3
টাইপগুলি (s / - /, / fmax ()) এ কমা অনুপস্থিত বাদে, এই বাস্তবায়নের শূন্যের নিকটে সংখ্যার জন্য একটি বাগ রয়েছে যা EPSILON এর মধ্যে রয়েছে, তবে এখনও বেশ ভার্সাল নয় AL উদাহরণস্বরূপ, আরেসেম (1.0E-10, 1.0E-9) মিথ্যা প্রতিবেদন করে কারণ আপেক্ষিক ত্রুটি বিশাল। আপনি আপনার সংস্থার নায়ক হতে পারেন।
brlcad

1
@ ব্রলক্যাড আপনি ভাসমান পয়েন্টটি পয়েন্ট পান নি। 1.0E-10 এবং 1.0E-9 10 মাত্রার দ্বারা পৃথক হয়। সুতরাং এটি সত্য যে এগুলি এক নয়। ভাসমান পয়েন্ট সবসময় আপেক্ষিক ত্রুটি সম্পর্কে । আপনার যদি এমন একটি সিস্টেম থাকে যা 1.0E-10 এবং 1.0E-9 কে প্রায় সমান হিসাবে বিবেচনা করে, যেহেতু উভয়ই "শূন্যের কাছাকাছি" (যা মানুষের কাছে যুক্তিসঙ্গত বলে মনে হয় তবে গাণিতিকভাবে কিছুই নয়) তবে EPSILON যথাযথ হিসাবে সামঞ্জস্য করা দরকার যেমন একটি সিস্টেমের জন্য।
ব্যবহারকারী 2261015

8

অন্যরা যেমন উল্লেখ করেছে, একটি স্থির-এক্সপোঞ্জেন্ট অ্যাপসিলন (যেমন 0.0000001) ব্যবহার করা এপিসিলন মান থেকে দূরে মানের জন্য অকেজো হবে । উদাহরণস্বরূপ, যদি আপনার দুটি মান 10000.000977 এবং 10000 হয়, তবে কোনও নেই 10000 এবং 10000,000977 হিসাবে আপনি সম্ভবত বিট বিট-জন্য অভিন্ন ছাড়া পেতে পারেন ঘনিষ্ঠ হিসাবে - এই দুটি সংখ্যার মধ্যে 32-বিট ফ্লোটিং পয়েন্ট মান। এখানে 0.0009 এরও কম ইপসিলন অর্থহীন; আপনি পাশাপাশি সরাসরি সাম্য অপারেটর ব্যবহার করতে পারেন।

একইভাবে, দুটি মান আকারে অ্যাপসিলনের কাছে যাওয়ার সাথে আপেক্ষিক ত্রুটিটি 100% এ বৃদ্ধি পায়।

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

আপনি যদি কোনও প্রকারের সংখ্যাসূচক প্রোগ্রামিং করেন এবং বিশ্বাস করেন যে আপনাকে ফিক্স-পয়েন্ট অ্যাপসিলনস পৌঁছাতে হবে, তবে ব্রাশের নিবন্ধটি ফ্ল্যাটিং-পয়েন্ট নম্বর সহ একত্র করুন

ভাসমান পয়েন্ট নম্বর তুলনা


5

কিউটি দুটি ফাংশন প্রয়োগ করে, সম্ভবত আপনি তাদের কাছ থেকে শিখতে পারেন:

static inline bool qFuzzyCompare(double p1, double p2)
{
    return (qAbs(p1 - p2) <= 0.000000000001 * qMin(qAbs(p1), qAbs(p2)));
}

static inline bool qFuzzyCompare(float p1, float p2)
{
    return (qAbs(p1 - p2) <= 0.00001f * qMin(qAbs(p1), qAbs(p2)));
}

এবং আপনার নিম্নলিখিত ফাংশনগুলির প্রয়োজন হতে পারে

নোট করুন যে যেখানে p1 বা p2 হয় 0 এর সাথে মানগুলি তুলনা করা কার্যকর হবে না, বা মানগুলির সাথে তুলনা করা হবে না যেখানে মানগুলির মধ্যে একটি NaN বা অনন্ত। মানগুলির মধ্যে যদি সর্বদা 0.0 থাকে তবে পরিবর্তে qFuzzyIsNull ব্যবহার করুন। মানগুলির মধ্যে একটি যদি 0.0 হয় বলে মনে হয় তবে একটি সমাধান হ'ল উভয় মানগুলিতে 1.0 যোগ করা।

static inline bool qFuzzyIsNull(double d)
{
    return qAbs(d) <= 0.000000000001;
}

static inline bool qFuzzyIsNull(float f)
{
    return qAbs(f) <= 0.00001f;
}

3

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


3

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

if (fabs(a - b) <= DBL_EPSILON * fmax(fabs(a), fabs(b)))
{
    // ...
}

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

if (fabs(a - b) <= 16 * DBL_EPSILON * fmax(fabs(a), fabs(b)))
{
    // ...
}

যদি তুলনামূলক পারফরম্যান্স আপনার পক্ষে খুব গুরুত্বপূর্ণ এবং আপনি আপনার মানগুলির সীমাটি জানেন তবে তার পরিবর্তে আপনার স্থির-পয়েন্ট নম্বর ব্যবহার করা উচিত।


2
“ইপিএসলন হ'ল সবচেয়ে ক্ষুদ্রতম মান যা ০.০ এ যুক্ত হতে পারে এবং এর মান পরিবর্তন করতে পারে": প্রকৃতপক্ষে, এই সম্মানটি 0.5 * ইপিএসলনের উত্তরসূরি (ডিফল্ট রাউন্ড টু-নিকটতম মোডে) যায়। blog.frama-c.com/index.php?post/2013/05/09/FLT_EPSILON
পাস্কেল কুয়াক

আপনি কেন মনে করেন যে EPSILONপ্রশ্নে DBL_EPSILONবা হয় FLT_EPSILON? সমস্যাটি আপনার নিজস্ব কল্পনার মধ্যে রয়েছে, যেখানে আপনি DBL_EPSILONকোডটি ব্যবহার করেন নি (যা প্রকৃত পক্ষে ভুল পছন্দ হবে) যা এটি ব্যবহার করে না।
বেন ভয়েগট

@ বেনওয়েগ্ট, আপনি ঠিক বলেছেন, এ সময়টি আমার মনে কিছু ছিল এবং আমি সেই আলোকে প্রশ্নের ব্যাখ্যাই দিয়েছিলাম।
ডন রেবা

2

আমার পোস্ট পূর্ববর্তী উত্তরের উপর ভিত্তি করে class গুগলের কোডের সাথে খুব অনুরূপ তবে আমি একটি পক্ষপাত ব্যবহার করি যা 0xFF000000 এর উপরে সমস্ত NaN মানকে ঠেলে দেয়। এটি NaN এর জন্য দ্রুত চেক করার অনুমতি দেয়।

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

typedef unsigned int   U32;
//  Float           Memory          Bias (unsigned)
//  -----           ------          ---------------
//   NaN            0xFFFFFFFF      0xFF800001
//   NaN            0xFF800001      0xFFFFFFFF
//  -Infinity       0xFF800000      0x00000000 ---
//  -3.40282e+038   0xFF7FFFFF      0x00000001    |
//  -1.40130e-045   0x80000001      0x7F7FFFFF    |
//  -0.0            0x80000000      0x7F800000    |--- Valid <= 0xFF000000.
//   0.0            0x00000000      0x7F800000    |    NaN > 0xFF000000
//   1.40130e-045   0x00000001      0x7F800001    |
//   3.40282e+038   0x7F7FFFFF      0xFEFFFFFF    |
//   Infinity       0x7F800000      0xFF000000 ---
//   NaN            0x7F800001      0xFF000001
//   NaN            0x7FFFFFFF      0xFF7FFFFF
//
//   Either value of NaN returns false.
//   -Infinity and +Infinity are not "close".
//   -0 and +0 are equal.
//
class CompareFloat{
public:
    union{
        float     m_f32;
        U32       m_u32;
    };
    static bool   CompareFloat::IsClose( float A, float B, U32 unitsDelta = 4 )
                  {
                      U32    a = CompareFloat::GetBiased( A );
                      U32    b = CompareFloat::GetBiased( B );

                      if ( (a > 0xFF000000) || (b > 0xFF000000) )
                      {
                          return( false );
                      }
                      return( (static_cast<U32>(abs( a - b ))) < unitsDelta );
                  }
    protected:
    static U32    CompareFloat::GetBiased( float f )
                  {
                      U32    r = ((CompareFloat*)&f)->m_u32;

                      if ( r & 0x80000000 )
                      {
                          return( ~r - 0x007FFFFF );
                      }
                      return( r + 0x7F800000 );
                  }
};

2

এখানে প্রমাণ যে ব্যবহার std::numeric_limits::epsilon() করা উত্তর নয় - এটি একের চেয়ে বেশি মানের জন্য ব্যর্থ হয়:

উপরে আমার মন্তব্যের প্রমাণ:

#include <stdio.h>
#include <limits>

double ItoD (__int64 x) {
    // Return double from 64-bit hexadecimal representation.
    return *(reinterpret_cast<double*>(&x));
}

void test (__int64 ai, __int64 bi) {
    double a = ItoD(ai), b = ItoD(bi);
    bool close = std::fabs(a-b) < std::numeric_limits<double>::epsilon();
    printf ("%.16f and %.16f %s close.\n", a, b, close ? "are " : "are not");
}

int main()
{
    test (0x3fe0000000000000L,
          0x3fe0000000000001L);

    test (0x3ff0000000000000L,
          0x3ff0000000000001L);
}

চলমান এই আউটপুট উত্পাদন করে:

0.5000000000000000 and 0.5000000000000001 are  close.
1.0000000000000000 and 1.0000000000000002 are not close.

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


আমি বিশ্বাস করি return *(reinterpret_cast<double*>(&x));যদিও এটি সচরাচর কাজ করে, বাস্তবে এটি অপরিবর্তিত আচরণ।
জাপ ভার্সটিঘ

ফেয়ার পয়েন্ট, যদিও এই কোডটি numeric_limits<>::epsilonচিত্রণযোগ্য তবে আইইইইই 754 ফ্লোরিং পয়েন্টের জন্য সমস্যাটি প্রদর্শন করতে যথেষ্ট ।
স্টিভ হলশ

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

1

এর উপরে আর একটি আকর্ষণীয় বাস্তবায়ন পাওয়া গেছে: https://en.cppreferences.com/w/cpp/tyype/numeric_limits/epsilon

#include <cmath>
#include <limits>
#include <iomanip>
#include <iostream>
#include <type_traits>
#include <algorithm>



template<class T>
typename std::enable_if<!std::numeric_limits<T>::is_integer, bool>::type
    almost_equal(T x, T y, int ulp)
{
    // the machine epsilon has to be scaled to the magnitude of the values used
    // and multiplied by the desired precision in ULPs (units in the last place)
    return std::fabs(x-y) <= std::numeric_limits<T>::epsilon() * std::fabs(x+y) * ulp
        // unless the result is subnormal
        || std::fabs(x-y) < std::numeric_limits<T>::min();
}

int main()
{
    double d1 = 0.2;
    double d2 = 1 / std::sqrt(5) / std::sqrt(5);
    std::cout << std::fixed << std::setprecision(20) 
        << "d1=" << d1 << "\nd2=" << d2 << '\n';

    if(d1 == d2)
        std::cout << "d1 == d2\n";
    else
        std::cout << "d1 != d2\n";

    if(almost_equal(d1, d2, 2))
        std::cout << "d1 almost equals d2\n";
    else
        std::cout << "d1 does not almost equal d2\n";
}

0

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

পোর্টেবল না থাকাকালীন, আমি মনে করি গ্রোমের উত্তর এই সমস্যাগুলি এড়ানো সবচেয়ে ভাল কাজ করে।


1
ভাল তথ্যের জন্য +1। তবে, আপেক্ষিক ত্রুটি বাড়িয়ে আপনি কীভাবে সাম্যের তুলনা নিয়ে গণ্ডগোল করতে পারেন তা দেখতে আমি ব্যর্থ; আইএমএইচও ত্রুটিটি কেবল বিয়োগের ফলেই তাৎপর্যপূর্ণ হয়ে ওঠে, তবে এটি দুটি অপারেন্ডের সাথে বিয়োগফলের তুলনায় বৃহত্তরতার ক্রমটি সাম্যের বিচারের পক্ষে যথেষ্ট নির্ভরযোগ্য হওয়া উচিত। রেজুলেশন বাদে সামগ্রিকভাবে উচ্চতর হওয়া প্রয়োজন, তবে সেক্ষেত্রে একমাত্র সমাধান হ'ল ম্যান্টিসায় আরও উল্লেখযোগ্য বিট সহ একটি ভাসমান বিন্দু উপস্থাপনে যাওয়া।
sehe

দুটি প্রায় সমান সংখ্যার বিয়োগ করা বিপর্যয়কর বাতিল হতে পারে না - বাস্তবে এটি কোনও ত্রুটি প্রবর্তন করে না (কিউভি স্টেরবেনজের উপপাদ্য)। বিপর্যয়কর বাতিল আগে aএবং bতাদের গণনার সময় ঘটে । অস্পষ্ট তুলনার অংশ হিসাবে ভাসমান বিন্দু
বিয়োগটি

0

সংখ্যাসূচক সফ্টওয়্যারটিতে এমন কয়েকটি ক্ষেত্রে রয়েছে যেখানে আপনি দুটি ভাসমান পয়েন্টের সংখ্যাটি ঠিক সমান কিনা তা পরীক্ষা করতে চান । আমি এটি একটি অনুরূপ প্রশ্ন পোস্ট

https://stackoverflow.com/a/10973098/1447411

সুতরাং আপনি বলতে পারবেন না যে "তুলনাডুবিলস 1" সাধারণভাবে ভুল।


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

0

আপনি তুলনাটি কতটা সুনির্দিষ্ট করতে চান তা নির্ভর করে। আপনি যদি একই সংখ্যার জন্য তুলনা করতে চান তবে কেবল == এর সাথে যান। (আপনি বাস্তবে একই নম্বরটি না চাইলে আপনি প্রায়শই এটি করতে চান না)) যে কোনও শালীন প্ল্যাটফর্মে আপনি নিম্নলিখিতগুলিও করতে পারেন:

diff= a - b; return fabs(diff)<EPSILON;

যেমন fabs বেশ দ্রুত হতে থাকে। বেশ দ্রুতগতির দ্বারা আমি বোঝাতে চাইছি এটি মূলত কিছুটা দিকের এবং তাই, এটি আরও দ্রুততর হয়।

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


0

পরিমাণের স্কেলের ক্ষেত্রে:

যদি epsilonকিছু নির্দিষ্ট শারীরিক অর্থে পরিমাণের (যেমন আপেক্ষিক মান) পরিমাণের ক্ষুদ্র ভগ্নাংশ হয় Aএবং Bপ্রকারগুলি একই অর্থে তুলনীয় হয়, তবে আমার মনে হয় যে নিম্নলিখিতটি বেশ সঠিক:

#include <limits>
#include <iomanip>
#include <iostream>

#include <cmath>
#include <cstdlib>
#include <cassert>

template< typename A, typename B >
inline
bool close_enough(A const & a, B const & b,
                  typename std::common_type< A, B >::type const & epsilon)
{
    using std::isless;
    assert(isless(0, epsilon)); // epsilon is a part of the whole quantity
    assert(isless(epsilon, 1));
    using std::abs;
    auto const delta = abs(a - b);
    auto const x = abs(a);
    auto const y = abs(b);
    // comparable generally and |a - b| < eps * (|a| + |b|) / 2
    return isless(epsilon * y, x) && isless(epsilon * x, y) && isless((delta + delta) / (x + y), epsilon);
}

int main()
{
    std::cout << std::boolalpha << close_enough(0.9, 1.0, 0.1) << std::endl;
    std::cout << std::boolalpha << close_enough(1.0, 1.1, 0.1) << std::endl;
    std::cout << std::boolalpha << close_enough(1.1,    1.2,    0.01) << std::endl;
    std::cout << std::boolalpha << close_enough(1.0001, 1.0002, 0.01) << std::endl;
    std::cout << std::boolalpha << close_enough(1.0, 0.01, 0.1) << std::endl;
    return EXIT_SUCCESS;
}

0

আমি এই কোডটি ব্যবহার করি:

bool AlmostEqual(double v1, double v2)
    {
        return (std::fabs(v1 - v2) < std::fabs(std::min(v1, v2)) * std::numeric_limits<double>::epsilon());
    }

2
এটা কি epsilonজন্য নয়।
স্নেফটেল

1
কেন না? তুমি কি এটা ব্যাখ্যা করতে পারবে?
ডেবুটি

2
@debuti epsilonনিছক 1 এবং 1. সেরা এ পরে পরবর্তী representable সংখ্যা মধ্যে দূরত্ব হল যে, কোড শুধু কি না চেক করতে দুই নম্বর আছে চেষ্টা করছে ঠিক একে অপরের সমান, কিন্তু 2 অ ক্ষমতা দ্বারা গুন করা হচ্ছে epsilon, এটা এমনকি এটি সঠিকভাবে করছে না।
স্নেফটেল

2
ওহ, এবং std::fabs(std::min(v1, v2))ভুল - নেতিবাচক ইনপুটগুলির জন্য এটি বৃহত্তর দৈর্ঘ্যের সাথে একটিকে বেছে নিয়েছে।
স্নেফটেল

0

আমি এটি জাভা জন্য লিখছি, তবে সম্ভবত আপনি এটি দরকারী মনে হয়। এটি ডাবলসের পরিবর্তে লম্বা ব্যবহার করে তবে এনএএন, সাবমনরমাল ইত্যাদির যত্ন নেয়

public static boolean equal(double a, double b) {
    final long fm = 0xFFFFFFFFFFFFFL;       // fraction mask
    final long sm = 0x8000000000000000L;    // sign mask
    final long cm = 0x8000000000000L;       // most significant decimal bit mask
    long c = Double.doubleToLongBits(a), d = Double.doubleToLongBits(b);        
    int ea = (int) (c >> 52 & 2047), eb = (int) (d >> 52 & 2047);
    if (ea == 2047 && (c & fm) != 0 || eb == 2047 && (d & fm) != 0) return false;   // NaN 
    if (c == d) return true;                            // identical - fast check
    if (ea == 0 && eb == 0) return true;                // ±0 or subnormals
    if ((c & sm) != (d & sm)) return false;             // different signs
    if (abs(ea - eb) > 1) return false;                 // b > 2*a or a > 2*b
    d <<= 12; c <<= 12;
    if (ea < eb) c = c >> 1 | sm;
    else if (ea > eb) d = d >> 1 | sm;
    c -= d;
    return c < 65536 && c > -65536;     // don't use abs(), because:
    // There is a posibility c=0x8000000000000000 which cannot be converted to positive
}
public static boolean zero(double a) { return (Double.doubleToLongBits(a) >> 52 & 2047) < 3; }

মনে রাখবেন যে বেশ কয়েকটি ভাসমান-পয়েন্ট অপারেশন হওয়ার পরে, সংখ্যাটি আমরা যা প্রত্যাশা করি তার থেকে অনেক আলাদা হতে পারে। এটি ঠিক করার জন্য কোনও কোড নেই।


0

এ কেমন?

template<typename T>
bool FloatingPointEqual( T a, T b ) { return !(a < b) && !(b < a); }

আমি বিভিন্ন পন্থা দেখেছি - তবে এটি কখনও দেখিনি, তাই আমি কোনও মন্তব্য শুনতে আগ্রহী!


এটি 1.99999999 এবং 1.99999998
মেহেদি

-1
/// testing whether two doubles are almost equal. We consider two doubles
/// equal if the difference is within the range [0, epsilon).
///
/// epsilon: a positive number (supposed to be small)
///
/// if either x or y is 0, then we are comparing the absolute difference to
/// epsilon.
/// if both x and y are non-zero, then we are comparing the relative difference
/// to epsilon.
bool almost_equal(double x, double y, double epsilon)
{
    double diff = x - y;
    if (x != 0 && y != 0){
        diff = diff/y; 
    }

    if (diff < epsilon && -1.0*diff < epsilon){
        return true;
    }
    return false;
}

আমি আমার ছোট প্রকল্পের জন্য এই ফাংশনটি ব্যবহার করেছি এবং এটি কাজ করে, তবে নিম্নলিখিতটি নোট করুন:

দ্বিগুণ নির্ভুল ত্রুটি আপনার জন্য একটি চমক তৈরি করতে পারে। ধরা যাক অ্যাপসিলন = 1.0e-6, তারপরে 1.0 এবং 1.000001 উপরের কোড অনুসারে সমান বিবেচনা করা উচিত নয়, তবে আমার মেশিনে ফাংশনটি তাদের সমান বলে বিবেচনা করে, এটি কারণ 1.000001 বাইনারি ফর্ম্যাটে অবিকল অনুবাদ করা যায় না, এটি সম্ভবত 1.0000009xxx। আমি এটি 1.0 এবং 1.0000011 দিয়ে পরীক্ষা করি এবং এবার আমি প্রত্যাশিত ফলাফল পেয়েছি।


-1

ল্যাম্বদা সহ এটি আরও একটি সমাধান:

#include <cmath>
#include <limits>

auto Compare = [](float a, float b, float epsilon = std::numeric_limits<float>::epsilon()){ return (std::fabs(a - b) <= epsilon); };

এটি অন্যান্য উত্তরগুলির অনেকের মতোই এটি হ'ল এটি ল্যাম্বডা এবং এর কোনও ব্যাখ্যা নেই, সুতরাং এটি উত্তর হিসাবে খুব বেশি মূল্য যোগ করে না।
stijn

-2

আমার উপায় সঠিক না হলেও দরকারী হতে পারে

উভয় ফ্লোটকে স্ট্রিংয়ে রূপান্তর করুন এবং তারপরে স্ট্রিং তুলনা করুন

bool IsFlaotEqual(float a, float b, int decimal)
{
    TCHAR form[50] = _T("");
    _stprintf(form, _T("%%.%df"), decimal);


    TCHAR a1[30] = _T(""), a2[30] = _T("");
    _stprintf(a1, form, a);
    _stprintf(a2, form, b);

    if( _tcscmp(a1, a2) == 0 )
        return true;

    return false;

}

অপারেটর ওভারলেডিংও করা যেতে পারে


+1: আরে, আমি এটি নিয়ে গেম প্রোগ্রামিং করতে যাচ্ছি না, তবে ব্রুস ডসনের ব্লগে (গ্রন্থ?: ডি) এই সমস্যাটি নিয়ে আপনি বেশ কয়েকবার এসেছিলেন এবং যদি আপনি আটকে থাকেন তবে রাউন্ড-ট্রিপিং ফ্লোটের ধারণাটি বেশ কয়েকবার এসেছে if একটি ঘর এবং কেউ আপনার মাথায় একটি বন্দুক রাখে এবং বলে "আরে আপনাকে দুটি ভাসমানগুলি এক্স এর উল্লেখযোগ্য পরিসংখ্যানের সাথে তুলনা করতে হবে, আপনার 5 মিনিট হবে, যাও!" এটি সম্ভবত বিবেচনা করা এক। ;)
শেললিবুটারফ্লাই

@ শেলিবাটারফ্লাই এরপরে আবার প্রশ্নটি ছিল দুটি ভাসমান পয়েন্ট সংখ্যার তুলনা করার সবচেয়ে কার্যকরী উপায়ের জন্য ।
টমি অ্যান্ডারসন

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

-2

আপনি doubleএকটি স্থির সঙ্গে দুটি তুলনা করতে পারবেন না EPSILON। মান উপর নির্ভর করে double, EPSILONপরিবর্তিত হয়।

আরও ভাল দ্বিগুণ তুলনা হবে:

bool same(double a, double b)
{
  return std::nextafter(a, std::numeric_limits<double>::lowest()) <= b
    && std::nextafter(a, std::numeric_limits<double>::max()) >= b;
}

-2

আরও সাধারণ উপায়ে:

template <typename T>
bool compareNumber(const T& a, const T& b) {
    return std::abs(a - b) < std::numeric_limits<T>::epsilon();
}

4
নম্বরগুলি যদি মত এই পদ্ধতি অনেক দুর্বলতা রয়েছে aএবং bতুলনায় ইতিমধ্যে ছোট epsilon()সেখানে পার্থক্য এখনও উল্লেখযোগ্য হতে পারে। বিপরীতভাবে যদি সংখ্যাগুলি খুব বড় হয় তবে কিছু সংখ্যক ত্রুটি এমনকি ত্বকে তুলনাটি ব্যর্থ করে দেবে এমনকি আপনি যদি সংখ্যাকে সমান বিবেচনা করতে চান তবেও। এই উত্তরটি হ'ল "জেনেরিক" তুলনা অ্যালগরিদমের ধরণ যা আপনি এড়াতে চান।
সিরগুই

-3

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


দয়া করে একাধিক প্রশ্নের একই উত্তর যুক্ত করবেন না। সেরাটির উত্তর দিন এবং বাকীটিকে সদৃশ হিসাবে চিহ্নিত করুন। মেটা.স্ট্যাকেক্সেঞ্জাওন.কম
রাও

আমি শুধু এক্সওআর (এবং এক বা দুটি তুলনা) ব্যবহার করে "এপসিলন তুলনা" সম্ভব বলে মনে করি না, এমনকি একই ফর্ম্যাটে সাধারণ উপস্থাপনার মধ্যেও সীমাবদ্ধ।
গ্রেইবার্ড
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.