2010-08-13 9 views
5

खोजने के लिए कोड लिखने का प्रयास कर रहा है मैं सी (यानी फ्लोट, डबल और लम्बा डबल) में विभिन्न फ़्लोटिंग पॉइंट प्रारूपों के लिए सटीक स्तर का पता लगाने की कोशिश कर रहा हूं।मशीन ईपीएसलॉन

#include <stdio.h> 
#define N 100000 

int main(void) 
{ 
    float max = 1.0, min = 0.0, test; 
    int i;        /* Counter for the conditional loop */ 

    for (i = 0; i < N; i++) { 
     test = (max + min)/2.0; 
     if((1.0 + test) != 1.0)   /* If too high, set max to test and try again */ 
    max = test; 
    if((1.0 + test) == 1.0)  /* If too low, set min to test and try again */ 
     min = test; 
    } 
    printf("The epsilon machine is %.50lf\n", max); 
    return 0; 
} 

यह ~ 2^-64 की उम्मीद के रूप में मोटे तौर पर की मूल्य देता है: यहाँ कोड मैं इस समय का उपयोग कर रहा है। हालांकि जब मैं डिकलेरेशंस को युगल या 'लंबे युगल' में बदलता हूं तो मुझे वही उत्तर मिलता है, मुझे एक छोटा सा मूल्य मिलना चाहिए लेकिन मैं नहीं करता हूं। किसी को कोई विचार है? ,

if((1.0 + test) != 1.0) 

यहाँ 1.0 एक डबल स्थिर है तो यह एक डबल करने के लिए अपने नाव को बढ़ावा देने और एक डबल के रूप में इसके अलावा प्रदर्शन कर रहा है:

+2

बदलाव नहीं होता से एक 23-बिट अपूर्णांश है? आप 2^-64 की अपेक्षा क्यों करेंगे? – Rup

उत्तर

2

एक अनुमान कारण है कि आप एक ही जवाब हो रही है। आप शायद अतिरिक्त प्रदर्शन करने के लिए अस्थायी फ्लोट घोषित करना चाहते हैं, या उन फ्लोट न्यूमेरिक स्थिरांक (1.0f आईआईआरसी) बना सकते हैं।

आप अतिरिक्त परिशुद्धता-अस्थायी-फ्लोट समस्या में भी पड़ सकते हैं और इसे सही परिशुद्धता को कम करने के लिए मध्यवर्ती को स्मृति में संग्रहीत करने के लिए मजबूर करने की आवश्यकता हो सकती है।


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

#include <stdio.h> 
#define N 100000 
#define TYPE float 

int main(void) 
{ 
    TYPE max = 1.0, min = 0.0, test; 
    int i; 

    for (i = 0; i < N; i++) 
    { 
     TYPE one_plus_test; 

     test = (max + min)/((TYPE)2.0); 
     one_plus_test = ((TYPE)1.0) + test; 
     if (one_plus_test == ((TYPE)1.0)) 
     { 
     min = test; 
     } 
     else 
     { 
     max = test; 
     } 
    } 
    printf("The epsilon machine is %.50lf\n", max); 
    return 0; 
} 
+0

मुझे लगता है कि कास्टिंग '(1.0 + टेस्ट) '' फ्लोट' तक इसे ठीक कर सकता है, लेकिन मुझे यकीन नहीं है .. –

+0

मैं इसे फ्लोट के रूप में कैसे डाल सकता हूं? मैं इसे एक बार दूंगा और देखें कि – JMzance

+0

क्या हुआ मैंने हाँ कोशिश की लेकिन यह अभी भी मुझे 2 और -64 – JMzance

2

मुझे यकीन नहीं है कि आपके एल्गोरिदम को कैसे काम करना चाहिए।

#include <iostream> 

template<typename T> 
int epsilon() { 
    int pow = 0; 
    T eps = 1; 
    while (eps + 1 != 1) { 
     eps /= 2; 
     --pow; 
    } 
    return pow + 1; 
} 

int main() { 
    std::cout << "Epsilon for float: 2^" << epsilon<float>() << '\n'; 
    std::cout << "Epsilon for double: 2^" << epsilon<double>() << '\n'; 
} 

यह सबसे छोटा मान ऐसी है कि, जब 1 को जोड़ा गया है, अभी भी अलग पहचाना से 1.

आउटपुट है गणना करता है:

Epsilon for float: 2^-23 
Epsilon for double: 2^-52 
+0

मैं जानता हूँ कि किसी भी सी ++ इम डर – JMzance

+0

यह kunderstand अगर आप सी पता टेम्पलेट सिर्फ मेरे बारे में' T' की सुविधा देता है और बहुत कठिन नहीं होना चाहिए न स्थानापन्न या तो 'float' या इसके लिए 'डबल'। और मुद्रण अलग-अलग काम करता है, लेकिन इसके बारे में चिंता न करें। – Thomas

0

एक यह एक (C++) सही जवाब देता है इस तरह के कोड के साथ समस्या यह है कि संकलक माइक्रोप्रोसेसर के फ्लोटिंग पॉइंट रजिस्टरों में फ़्लोटिंग पॉइंट वेरिएबल्स लोड करेगा। और यदि आपके माइक्रोप्रोसेसर में केवल डबल परिशुद्धता फ़्लोटिंग पॉइंट रजिस्ट्रार हैं, तो सटीकता float और double के लिए समान होगी।

आपको प्रत्येक दो गणनाओं (सही प्रकार के चर के बीच) में फ्लोटिंग पॉइंट मान को स्मृति में वापस स्टोर करने के लिए कंपाइलर को मजबूर करने का एक तरीका खोजने की आवश्यकता होगी। इस तरह इसे रजिस्टरों की अतिरिक्त परिशुद्धता को फेंकना पड़ता है। लेकिन आज के कंपाइलर्स आपके कोड को अनुकूलित करने में चालाक हैं। तो यह हासिल करना मुश्किल हो सकता है।

+0

हममम दिलचस्प है, मैं एक बकवास संकलक का उपयोग कर की कोशिश कर सकते! lol – JMzance

+0

क्यों सिर्फ डिबग मोड या इसी तरह का संकलन नहीं, कि ऑप्टिमाइज़ेशन निष्पादित नहीं करता है? – PeMa

8

यह "सटीक स्तर" से आपका क्या मतलब है इस पर निर्भर करता है।

फ़्लोटिंग-पॉइंट नंबरों में "नियमित" (सामान्य) मान होते हैं, लेकिन विशेष, उप-सामान्य संख्याएं भी होती हैं।

#include <math.h> 
#include <stdio.h> 
#include <float.h> 

int main(void) 
{ 
    printf("%30s: %g\n", "FLT_EPSILON", FLT_EPSILON); 
    printf("%30s: %g\n", "FLT_MIN", FLT_MIN); 
    printf("%30s: %g\n", "nextafterf(0.0, 1.0)", nextafterf(0.0, 1.0)); 
    printf("%30s: %g\n", "nextafterf(1.0, 2.0)-1", (nextafterf(1.0, 2.0) - 1.0f)); 
    puts(""); 
    printf("%30s: %g\n", "DBL_EPSILON", DBL_EPSILON); 
    printf("%30s: %g\n", "DBL_MIN", DBL_MIN); 
    printf("%30s: %g\n", "nextafter(0.0, 1.0)", nextafter(0.0, 1.0)); 
    printf("%30s: %g\n", "nextafter(1.0, 2.0)-1", (nextafter(1.0, 2.0) - 1.0)); 
    puts(""); 
    printf("%30s: %Lg\n", "LDBL_EPSILON", LDBL_EPSILON); 
    printf("%30s: %Lg\n", "LDBL_MIN", LDBL_MIN); 
    printf("%30s: %Lg\n", "nextafterl(0.0, 1.0)", nextafterl(0.0, 1.0)); 
    printf("%30s: %Lg\n", "nextafterl(1.0, 2.0)-1", (nextafterl(1.0, 2.0) - 1.0)); 
    return 0; 
} 

उपरोक्त कार्यक्रम प्रिंट प्रत्येक प्रकार के लिए 4 मूल्यों:

  • 1 के बीच का अंतर और कम से कम मूल्य 1 से अधिक आप अलग अलग सीमा पता लगाने के लिए चाहते हैं, सी मानक पूर्वनिर्धारित स्थिरांक है उस प्रकार (प्रकार_EPSILON),
  • न्यूनतम एक दिया प्रकार (प्रकार_MIN) में सकारात्मक सामान्यीकृत मान में। इसमें subnormal numbers,
  • किसी दिए गए प्रकार (nextafter * (0 ... )) में न्यूनतम सकारात्मक मान शामिल नहीं है। इसमें असामान्य संख्याएं,
  • न्यूनतम संख्या 1 से अधिक है। यह TYPE_EPSILON जैसा ही है, लेकिन एक अलग तरीके से गणना की जाती है।

"सटीक" से आपका क्या मतलब है, इस पर निर्भर करता है कि उपरोक्त में से कोई भी या कोई भी आपके लिए उपयोगी नहीं हो सकता है।

   FLT_EPSILON: 1.19209e-07 
        FLT_MIN: 1.17549e-38 
     nextafterf(0.0, 1.0): 1.4013e-45 
    nextafterf(1.0, 2.0)-1: 1.19209e-07 

       DBL_EPSILON: 2.22045e-16 
        DBL_MIN: 2.22507e-308 
     nextafter(0.0, 1.0): 4.94066e-324 
    nextafter(1.0, 2.0)-1: 2.22045e-16 

       LDBL_EPSILON: 1.0842e-19 
        LDBL_MIN: 3.3621e-4932 
     nextafterl(0.0, 1.0): 3.6452e-4951 
    nextafterl(1.0, 2.0)-1: 1.0842e-19 
+0

चीयर्स, im खुशी है कि सी में इस के लिए बनाया गया है बात। हालांकि मेरा काम एक फ्लोटिंग नंबर द्वारा प्रतिनिधित्व किए जा सकने वाले एक से अधिक छोटे मूल्य को खोजने के लिए एक कोड लिखना है। वहां पहला नंबर: 1.19209e-07 वह मुझे उम्मीद है, लेकिन किसी कारण से मेरा कोड मुझे यह नहीं देता है। मैनी धन्यवाद – JMzance

+0

@ जैक: ठीक है। फिर आपको यह सुनिश्चित करना चाहिए कि आपकी गणना में उपयोग की जाने वाली सभी फ़्लोटिंग पॉइंट संख्याएं 'फ्लोट' मान हैं। तो '1.0 + परीक्षण करने के बजाय! = 1.0', मैं करूँगा: 'फ्लोट प्रयास = 1.0 + परीक्षण; अगर (कोशिश करो! = 1.0) ', आदि –

+0

चियर्स लोग, अपनी शुरुआती समझदार जवाब देने के लिए अब – JMzance

1

मैं जोड़ने के लिए है कि आप long double का उपयोग करके एक चल बिन्दु गणना से उच्चतम परिशुद्धता प्राप्त कर सकते हैं करना चाहते हैं:

यहाँ अपने कंप्यूटर पर उपरोक्त कार्यक्रम के उत्पादन में है।

@ करने के लिए Rup के समाधान है कि लागू करने के लिए, बस TYPElong double करने के लिए और printf बयान बदलने के लिए:

0.00000005960465188081798260100185871124267578125000 

और का उपयोग कर:

printf("The epsilon machine is %.50Lf\n", max); 

यह मेरा मशीन float के प्रयोग पर एप्सिलॉन है long double:

0.00000000000000000005421010862427522170625011179761 

अंतर काफी महत्वपूर्ण है।

2

आईईईई 754 फ्लोटिंग-पॉइंट प्रारूपों में संपत्ति है, जब एक ही चौड़ाई के दो पूरक पूरक पूर्णांक के रूप में पुन: व्याख्या की जाती है, तो वे सकारात्मक मूल्यों पर एकान्त रूप से वृद्धि करते हैं और नकारात्मक मूल्यों पर एकान्त रूप से कमी करते हैं (32 बिट फ्लोट्स के बाइनरी प्रतिनिधित्व देखें)। उनके पास संपत्ति भी है| एफ (एक्स) | < ∞, और | एफ (एक्स + 1) - एफ (एक्स) | ≥ | एफ (एक्स) - एफ (एक्स -1) | (जहां एफ (एक्स) एक्स का उपरोक्त पूर्णांक पुनरावृत्ति है)। ऐसी भाषाओं में जो टाइपिंग की अनुमति देते हैं और हमेशा आईईईई 754-19 85 का उपयोग करते हैं, हम निरंतर समय में मशीन ईपीएसलॉन की गणना करने के लिए इसका फायदा उठा सकते हैं। उदाहरण के लिए, C:

typedef union { 
    long long i64; 
    double d64; 
} dbl_64; 

double machine_eps (double value) 
{ 
    dbl_64 s; 
    s.d64 = value; 
    s.i64++; 
    return s.d64 - value; 
} 

https://en.wikipedia.org/wiki/Machine_epsilon

संबंधित मुद्दे