एप्सिलॉन का उपयोग कर दोहरे से शून्य की तुलना करें


214

आज, मैं कुछ सी ++ कोड (किसी और द्वारा लिखित) के माध्यम से देख रहा था और इस खंड को पाया:

double someValue = ...
if (someValue <  std::numeric_limits<double>::epsilon() && 
    someValue > -std::numeric_limits<double>::epsilon()) {
  someValue = 0.0;
}

मैं यह पता लगाने की कोशिश कर रहा हूं कि क्या यह भी समझ में आता है।

के लिए प्रलेखन epsilon()कहता है:

फ़ंक्शन 1 और सबसे छोटे मूल्य के बीच का अंतर 1 से अधिक देता है जो कि प्रतिनिधित्व योग्य है [एक डबल द्वारा]।

क्या यह ० पर भी लागू होता है, यानी epsilon()० से बड़ा सबसे छोटा मान है? या वहाँ के बीच संख्या है 0और 0 + epsilonकहा कि एक द्वारा प्रतिनिधित्व किया जा सकता है double?

यदि नहीं, तो तुलना के बराबर नहीं है someValue == 0.0?


3
1 के आसपास एप्सिलॉन की संभावना 0 के आसपास की तुलना में बहुत अधिक होगी, इसलिए संभवतः 0 और 0 + epsilon_at_1 के बीच मान होंगे। मुझे लगता है कि इस खंड के लेखक कुछ छोटा उपयोग करना चाहते थे, लेकिन वह एक जादू का उपयोग नहीं करना चाहते थे, इसलिए उन्होंने सिर्फ अनिवार्य रूप से मनमाना मूल्य का उपयोग किया।
enobayram 8

2
फ्लोटिंग पॉइंट संख्याओं की तुलना करना कठिन है, और एप्सिलॉन या थ्रेशोल्ड वैल्यू के उपयोग को भी प्रोत्साहित किया जाता है। कृपया देखें: cs.princeton.edu/introcs/91float और cygnus-software.com/papers/comparingfloats/comparingfloats.htm
आदित्य कुमार पांडेय

40
पहला लिंक 403.99999999
graham.reeds

6
IMO, इस मामले में उपयोग numeric_limits<>::epsilonभ्रामक और अप्रासंगिक है। हम जो चाहते हैं उसे 0 मान लेना है यदि वास्तविक मान 0. से कुछ assume से अधिक नहीं है और समस्या के विनिर्देश के आधार पर चुना जाना चाहिए, मशीन-निर्भर मूल्य पर नहीं। मुझे संदेह है कि वर्तमान एप्सिलॉन बेकार है, क्योंकि कुछ एफपी ऑपरेशन भी इससे बड़ी त्रुटि जमा कर सकते हैं।
एंड्री विह्रोव

1
+1। एप्सिलॉन सबसे छोटा संभव नहीं है, लेकिन अधिकांश व्यावहारिक इंजीनियरिंग कार्यों में दिए गए उद्देश्य की सेवा कर सकते हैं यदि आप जानते हैं कि आपको क्या सटीकता की आवश्यकता है और आप क्या कर रहे हैं।
SChepurin

जवाबों:


192

64-बिट IEEE डबल मानते हुए, 52-बिट मंटिसा और 11-बिट एक्सपोर्टर है। चलो इसे बिट्स के लिए तोड़ो:

1.0000 00000000 00000000 00000000 00000000 00000000 00000000 × 2^0 = 1

सबसे छोटी प्रतिनिधित्व योग्य संख्या 1 से अधिक है:

1.0000 00000000 00000000 00000000 00000000 00000000 00000001 × 2^0 = 1 + 2^-52

इसलिए:

epsilon = (1 + 2^-52) - 1 = 2^-52

क्या 0 और एप्सिलॉन के बीच कोई संख्या है? बहुत ... उदाहरण के लिए न्यूनतम धनात्मक प्रतिनिधित्व योग्य (सामान्य) संख्या है:

1.0000 00000000 00000000 00000000 00000000 00000000 00000000 × 2^-1022 = 2^-1022

वास्तव में (1022 - 52 + 1)×2^52 = 43729952381767516160 और एप्सिलॉन के बीच संख्याएं हैं , जो कि सभी सकारात्मक प्रतिनिधित्व योग्य संख्याओं का 47% है ...


27
इतना अजीब कि आप "सकारात्मक संख्या का 47%" कह सकते हैं :)
विन्यासकर्ता

13
@configurator: नहीं, आप ऐसा नहीं कह सकते (कोई 'प्राकृतिक' परिमित माप मौजूद नहीं है)। लेकिन आप कह सकते हैं "सकारात्मक प्रतिनिधित्व योग्य संख्या का 47% "।
याकॉव गल्का

1
@ybungalobill मैं इसका पता नहीं लगा सकता। घातांक में 11 बिट्स होते हैं: 1 साइन बिट और 10 मूल्य बिट्स। 2 ^ -1022 और 2 ^ -1024 सबसे छोटी धनात्मक संख्या क्यों है?
पावलो डायबन

3
@PavloDyban: सिर्फ इसलिए कि प्रतिपादकों के पास साइन बिट नहीं है। उन्हें ऑफ़सेट के रूप में एन्कोड किया गया है: यदि एन्कोडेड एक्सपोनेंट है 0 <= e < 2048तो मैन्टिसा को 2 की शक्ति से गुणा किया जाता है e - 1023। उदाहरण के घटक के 2^0रूप में e=1023, के 2^1रूप में e=1024और के 2^-1022रूप में एन्कोडेड है e=1। का मूल्य e=0सबनर्मल और वास्तविक शून्य के लिए आरक्षित है।
याकॉव गल्का

2
@PavloDyban: भी 2^-1022सबसे छोटी सामान्य संख्या है। सबसे छोटी संख्या वास्तव में है 0.0000 00000000 00000000 00000000 00000000 00000000 00000001 × 2^-1022 = 2^-1074। यह उप-असामान्य है, जिसका अर्थ है कि मंटिसा भाग 1 से छोटा है, इसलिए यह घातांक के साथ एन्कोडेड है e=0
याकॉव गल्का

17

परीक्षण निश्चित रूप से जैसा नहीं है someValue == 0। फ्लोटिंग-पॉइंट नंबरों का पूरा विचार यह है कि वे एक घातांक और एक महत्व को संग्रहीत करते हैं। इसलिए वे सटीकता की एक निश्चित संख्या के द्विआधारी महत्वपूर्ण आंकड़ों के साथ एक मूल्य का प्रतिनिधित्व करते हैं (आईईईई डबल के मामले में 53)। प्रतिनिधित्व करने योग्य मान 0 के पास होने की तुलना में बहुत अधिक घनी हैं।

एक अधिक परिचित दशमलव प्रणाली का उपयोग करने के लिए, मान लें कि आपने घातांक के साथ एक दशमलव मान "4 महत्वपूर्ण आंकड़े" स्टोर किया है। फिर अगला प्रतिनिधित्व योग्य मूल्य इससे अधिक 1है 1.001 * 10^0, और epsilonहै 1.000 * 10^-3। लेकिन 1.000 * 10^-4यह भी प्रतिनिधित्व योग्य है, यह मानते हुए कि प्रतिपादक -4 को स्टोर कर सकता है। आप इसके लिए मेरा शब्द ले सकते हैं कि एक IEEE डबल घातांक की तुलना में कम मात्रा में स्टोर कर सकता है epsilon

आप अकेले इस कोड से यह नहीं बता सकते हैं कि यह epsilonविशेष रूप से बाध्य के रूप में उपयोग करने के लिए समझ में आता है या नहीं , आपको संदर्भ को देखने की आवश्यकता है। यह हो सकता है कि epsilonगणना में उत्पन्न त्रुटि का एक उचित अनुमान है someValue, और यह हो सकता है कि यह नहीं है।


2
अच्छी बात है, लेकिन अगर ऐसा है तो भी, एक बेहतर अभ्यास यह होगा कि त्रुटि को यथोचित रूप से नामित चर में रखा जाए और तुलना में उसका उपयोग किया जाए। जैसा कि यह खड़ा है, यह एक जादू स्थिरांक से अलग नहीं है।
enobayram 8

शायद मुझे अपने प्रश्न में स्पष्ट होना चाहिए था: मैंने यह सवाल नहीं किया कि क्या कम्प्यूटेशनल त्रुटि को कवर करने के लिए एप्सिलॉन काफी बड़ा "थ्रेसहोल्ड" था लेकिन क्या यह तुलना बराबर है someValue == 0.0या नहीं।
सेबेस्टियन क्रिम्समैस्की

13

ऐसी संख्याएं हैं जो 0 और एप्सिलॉन के बीच मौजूद हैं क्योंकि एप्सिलॉन 1 और अगले उच्चतम संख्या के बीच का अंतर है जिसे 1 से ऊपर दर्शाया जा सकता है और 0 और अगले उच्चतम संख्या के बीच का अंतर जो 0 से ऊपर का प्रतिनिधित्व किया जा सकता है (यदि ऐसा था, तो) कोड बहुत कम होगा): -

#include <limits>

int main ()
{
  struct Doubles
  {
      double one;
      double epsilon;
      double half_epsilon;
  } values;

  values.one = 1.0;
  values.epsilon = std::numeric_limits<double>::epsilon();
  values.half_epsilon = values.epsilon / 2.0;
}

डिबगर का उपयोग करना, मुख्य के अंत में प्रोग्राम को रोकें और परिणामों को देखें और आप देखेंगे कि एप्सिलॉन / 2 एप्सिलॉन, शून्य और एक से अलग है।

इसलिए यह फ़ंक्शन +/- एप्सिलॉन के बीच मान लेता है और उन्हें शून्य बनाता है।


5

एक नंबर (1.0, 0.0, ...) के आसपास एप्सिलॉन (सबसे छोटा संभव अंतर) का एकप्रकरण निम्नलिखित कार्यक्रम के साथ मुद्रित किया जा सकता है। यह निम्नलिखित आउटपुट को प्रिंट करता है:
epsilon for 0.0 is 4.940656e-324
epsilon for 1.0 is 2.220446e-16
एक छोटी सी सोच यह स्पष्ट करती है, कि एप्सिलॉन जितना छोटा होता है, हम उसके एप्सिलॉन-मूल्य को देखने के लिए उतने ही छोटे नंबर का उपयोग करते हैं, क्योंकि एक्सपोनेंट उस संख्या के आकार को समायोजित कर सकता है।

#include <stdio.h>
#include <assert.h>
double getEps (double m) {
  double approx=1.0;
  double lastApprox=0.0;
  while (m+approx!=m) {
    lastApprox=approx;
    approx/=2.0;
  }
  assert (lastApprox!=0);
  return lastApprox;
}
int main () {
  printf ("epsilon for 0.0 is %e\n", getEps (0.0));
  printf ("epsilon for 1.0 is %e\n", getEps (1.0));
  return 0;
}

2
आपने किन क्रियान्वयनों की जाँच की है? यह निश्चित रूप से जीसीसी 4.7 के लिए मामला नहीं है।
एंटोन गोलोव डिक

3

मान लीजिए कि हम खिलौना फ़्लोटिंग पॉइंट नंबरों के साथ काम कर रहे हैं जो 16 बिट रजिस्टर में फिट होते हैं। एक संकेत बिट, एक 5 बिट घातांक और 10 बिट mantissa है।

इस फ्लोटिंग पॉइंट संख्या का मान बाइनरी दशमलव मान के रूप में व्याख्या किए गए मंटिसा है, जो घातांक की शक्ति से दो गुना है।

लगभग 1 प्रतिपादक शून्य के बराबर है। तो मंटिसा का सबसे छोटा अंक 1024 में एक हिस्सा है।

१/२ के पास प्रतिपादक माइनस एक है, इसलिए मंटिसा का सबसे छोटा हिस्सा आधा बड़ा है। पांच बिट घातांक के साथ यह नकारात्मक 16 तक पहुंच सकता है, जिस बिंदु पर मंटिसा का सबसे छोटा हिस्सा 32 मी में एक भाग के लायक है। और नकारात्मक 16 घातांक पर, मान 32k में एक भाग के आसपास है, जो हमने ऊपर गणना की थी उसके चारों ओर एप्सिलॉन की तुलना में शून्य के करीब!

अब यह एक खिलौना फ़्लोटिंग पॉइंट मॉडल है जो एक वास्तविक फ़्लोटिंग पॉइंट सिस्टम के सभी quirks को प्रतिबिंबित नहीं करता है, लेकिन एप्सिलॉन की तुलना में छोटे मूल्यों को प्रतिबिंबित करने की क्षमता वास्तविक फ्लोटिंग पॉइंट मूल्यों के साथ समान है।


3

के बीच Xऔर अगले मूल्य के बीच का Xअंतर भिन्न होता है X
epsilon()केवल बीच का अंतर है 1और के अगले मूल्य 1
के बीच 0और अगले मूल्य में अंतर 0नहीं है epsilon()

इसके बजाय आप निम्न के std::nextafterसाथ एक दोहरे मूल्य की तुलना करने के लिए उपयोग कर सकते हैं 0:

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;
}

double someValue = ...
if (same (someValue, 0.0)) {
  someValue = 0.0;
}

2

मुझे लगता है कि आपके कंप्यूटर की शुद्धता पर निर्भर करता है । इस तालिका पर एक नज़र डालें : आप देख सकते हैं कि यदि आपके एप्सिलॉन का प्रतिनिधित्व दोगुना है, लेकिन आपकी सटीकता अधिक है, तो तुलना बराबर नहीं है

someValue == 0.0

वैसे भी अच्छा सवाल!


2

मन्तिसा और प्रतिपादक भागों के कारण आप इसे 0 पर लागू नहीं कर सकते। घातांक के कारण आप बहुत कम संख्या में स्टोर कर सकते हैं, जो एप्सिलॉन से छोटे होते हैं, लेकिन जब आप कुछ करने की कोशिश करते हैं (1.0 - "बहुत कम संख्या") तो आपको 1.0 मिलेगा। एप्सिलॉन एक संकेतक है जो मूल्य का नहीं है, बल्कि मूल्य परिशुद्धता का है, जो मंटिसा में है। यह दिखाता है कि हम कितनी संख्या में सही दशमलव दशमलव अंक जमा कर सकते हैं।


2

आईईईई फ्लोटिंग-पॉइंट के साथ, सबसे छोटे गैर-शून्य सकारात्मक मूल्य और सबसे छोटे गैर-शून्य नकारात्मक मूल्य के बीच, दो मान मौजूद हैं: सकारात्मक शून्य और नकारात्मक शून्य। परीक्षण करना कि क्या मूल्य शून्य से छोटे गैर-शून्य मानों के बीच है, शून्य के साथ समानता के लिए परीक्षण के बराबर है; हालाँकि, असाइनमेंट का प्रभाव पड़ सकता है, क्योंकि यह एक नकारात्मक शून्य को सकारात्मक शून्य में बदल देगा।

यह अनुमान योग्य होगा कि एक फ्लोटिंग-पॉइंट प्रारूप में छोटे परिमित सकारात्मक और नकारात्मक मानों के बीच तीन मान हो सकते हैं: सकारात्मक infinitesimal, अहस्ताक्षरित शून्य और नकारात्मक infinitesimal। मैं किसी भी फ्लोटिंग-पॉइंट फॉर्मेट्स से परिचित नहीं हूं जो वास्तव में उस तरह से काम करता है, लेकिन इस तरह का व्यवहार IEEE की तुलना में पूरी तरह से उचित और यकीनन बेहतर होगा (शायद यह समर्थन करने के लिए अतिरिक्त हार्डवेयर जोड़ने के लायक होने के लिए पर्याप्त नहीं है, लेकिन गणितीय रूप से 1 / (1 / INF), 1 / (- 1 / INF), और 1 / (1-1) को तीन अलग-अलग शून्य दर्शाते हुए तीन अलग-अलग मामलों का प्रतिनिधित्व करना चाहिए)। मुझे नहीं पता कि क्या कोई सी मानक जनादेश पर हस्ताक्षर करने वाले को अनिवार्य करेगा, यदि वे मौजूद हैं, तो उन्हें शून्य के बराबर तुलना करना होगा। यदि वे नहीं करते हैं, तो उपरोक्त जैसा कोड उपयोगी तरीके से सुनिश्चित कर सकता है कि जैसे


शून्य के बजाय "1 / (1-1)" (आपके उदाहरण से) अनंत नहीं है?
सेबस्टियन क्रिम्समैस्की

मात्रा (1-1), (1 / INF), और (-1 / INF) सभी शून्य का प्रतिनिधित्व करते हैं, लेकिन उनमें से प्रत्येक द्वारा एक सकारात्मक संख्या को विभाजित करने से सिद्धांत रूप में तीन अलग-अलग परिणाम प्राप्त होने चाहिए (IEEE गणित पहले दो को समान मानता है )।
सुपरैट

1

तो मान लीजिए कि प्रणाली 1.000000000000000000000 और 1.000000000000000000001 में अंतर नहीं कर सकती है। यह 1.0 और 1.0 + 1e-20 है। क्या आपको लगता है कि अभी भी कुछ मूल्य हैं जिन्हें -1e-20 और + 1e-20 के बीच दर्शाया जा सकता है?


शून्य को छोड़कर, मुझे नहीं लगता कि -1e-20 और + 1e-20 के बीच मान हैं। लेकिन सिर्फ इसलिए कि मुझे लगता है कि यह सच नहीं है।
सेबेस्टियन क्रिम्समैस्की

@ सेबेस्टियन क्रिम्समैस्की: यह सच नहीं है, 0 और के बीच बहुत सारे फ्लोटिंग-पॉइंट वैल्यू हैं epsilon। क्योंकि यह फ्लोटिंग पॉइंट है, फिक्स्ड पॉइंट नहीं है।
स्टीव जेसोप

सबसे छोटा प्रतिनिधित्व योग्य मूल्य जो शून्य से अलग है, घातांक का प्रतिनिधित्व करने के लिए आवंटित बिट्स की संख्या तक सीमित है। इसलिए यदि डबल में 11 बिट एक्सपोनेंट है, तो सबसे छोटी संख्या 1e-1023 होगी।
कैबबुंगा

0

इसके अलावा, इस तरह के एक समारोह होने का एक अच्छा कारण "विकृतीकरण" (उन बहुत कम संख्याओं को दूर करना है जो अब निहित "1" का उपयोग नहीं कर सकते हैं और एक विशेष एफपी प्रतिनिधित्व है)। तुमने ऐसा क्यों करना चाहोगे? क्योंकि कुछ मशीनें (विशेष रूप से, कुछ पुराने पेंटियम 4 जी) सच में बहुत धीमी हो जाती हैं, जब वे denormals प्रसंस्करण करते हैं। दूसरों को बस कुछ धीमा मिलता है। यदि आपके एप्लिकेशन को वास्तव में इन बहुत छोटी संख्याओं की आवश्यकता नहीं है, तो उन्हें शून्य पर फ्लश करना एक अच्छा समाधान है। विचार करने के लिए अच्छी जगहें किसी भी IIR फ़िल्टर या क्षय फ़ंक्शंस के अंतिम चरण हैं।

इसे भी देखें: 10x से 0.1f को 0 धीमा करने के लिए प्रदर्शन क्यों बदल रहा है?

और http://en.wikipedia.org/wiki/Denormal_number


1
यह केवल अपभ्रंश संख्याओं की तुलना में कई और संख्याओं को निकालता है। यह प्लैंक के स्थिर या इलेक्ट्रॉन के द्रव्यमान को शून्य में बदल देता है जो आपको इन नंबरों का उपयोग करने पर बहुत, बहुत गलत परिणाम देगा।
gnasher729
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.