क्यों num_limits मशीन एप्सिलॉन 1 + ई> 1 स्थिति को संतुष्ट नहीं करता है?

Dec 24 2020

अगर मैं गलत नहीं हूँ मशीन Epsilon की परिभाषा सबसे कम संख्या है जो स्थिति को संतुष्ट करती है:

मैं इस उपयोग का परीक्षण करने की कोशिश कर रहा था, std::numeric_limits<float>::epsilon()लेकिन मूल्य इस पर व्यंग्य नहीं करता है, यदि आप इसके लिए पूर्व फ्लोट संख्या प्राप्त करने का प्रयास करते हैं std::nextafter:

#include <cmath>
#include <iostream>
#include <limits>

int main() {
    float e = std::numeric_limits<float>::epsilon();
    float previous = std::nextafter(e, -std::numeric_limits<float>::infinity());

    std::cout << std::boolalpha << ((1.0f + previous) > 1.0f) << std::endl;

    return 0;
}

यह आउटपुट देता है true https://coliru.stacked-crooked.com/a/841e19dafcf0bf6f।

नंबर का उपयोग करने की कोशिश करने के बाद std::nextafterमैंने देखा कि उचित मशीन एप्सिलॉन होना चाहिए:

std::nextafter(std::numeric_limits<float>::epsilon() / 2.0f, std::numeric_limits<float>::infinity())

मैंने इस कोड का उपयोग करके इसका परीक्षण किया:

#include <cmath>
#include <iostream>
#include <limits>

bool verify(float e) {
    return ((1.0f + e) > 1.0f);
}

int main() {
    std::cout.precision(std::numeric_limits<float>::digits);
    std::cout << std::boolalpha << std::fixed;

    float epsilon = std::numeric_limits<float>::epsilon();

    float last = epsilon;
    while (true) {
        last = std::nextafter(last, -std::numeric_limits<float>::infinity());
        if ((1.0f + last) > 1.0f) {
            epsilon = last;
        } else {
            break;
        }
    }

    // Does not satisfy condition
    std::cout << "last: " << verify(last) << " " << last << std::endl;
    // Satisfy condition
    std::cout << "epsilon: " << verify(epsilon) << " " << epsilon << std::endl;

    float half_epsilon = std::numeric_limits<float>::epsilon() / 2.0f;
    float actual_epsilon = std::nextafter(half_epsilon, std::numeric_limits<float>::infinity());
    // Same as 'last' at this point
    std::cout << "half_epsilon: " << verify(half_epsilon) << " " << half_epsilon << std::endl;
    // Same as 'epsilon' at this point
    std::cout << "actual_epsilon: " << verify(actual_epsilon) << " " << actual_epsilon << std::endl;

    return 0;
}

यह आउटपुट

last: false 0.000000059604644775390625
epsilon: true 0.000000059604651880817983
half_epsilon: false 0.000000059604644775390625
actual_epsilon: true 0.000000059604651880817983

https://coliru.stacked-crooked.com/a/3c66a2144e80a91b

क्या मैं किसी दिन यहां गायब हूं?

जवाब

6 JaMiT Dec 24 2020 at 11:46

यदि मैं गलत नहीं हूँ तो मशीन एप्सिलॉन की परिभाषा सबसे कम संख्या है जो स्थिति को संतुष्ट करती है: [ 1 + epsilon > 1]

बंद करें, लेकिन आप C ++ के संदर्भ में गलत हैं। (मेरा मानना ​​है कि आपकी परिभाषा अन्य, अधिक अकादमिक संदर्भों में सही है।) cppreference.com के अनुसार , मशीन एप्सिलॉन " 1.0निर्दिष्ट [फ़्लोटिंग-पॉइंट प्रकार" के द्वारा और अगले मूल्य के बीच का अंतर है । " मशीन एप्सिलॉन संतुष्ट करता है 1 + epsilon > 1, लेकिन इसे सबसे कम संख्या की आवश्यकता नहीं है जो इसे संतुष्ट करता है। हालांकि, यह सबसे कम संख्या है जो सभी राउंडिंग मोड के तहत उस स्थिति को संतुष्ट करता है

क्योंकि मशीन एप्सिलॉन की तुलना में बहुत छोटी है 1.0, एप्सिलॉन और के बीच बहुत अधिक प्रतिनिधित्व योग्य मूल्य हैं 0.0। (यह फ़्लोटिंग पॉइंट अभ्यावेदन का एक मूल लक्ष्य है।) जब इनमें से किसी को भी जोड़ा जाता है 1.0, तो परिणाम प्रस्तुत करने योग्य नहीं होता है, इसलिए परिणाम को गोल करने की आवश्यकता होती है। यदि राउंडिंग मोड निकटतम प्रतिनिधित्व योग्य मान के लिए है, तो वह योग 1 + epsilonजब भी छोटी संख्या के बीच epsilon/2और उसके पास होगा 3*epsilon/2। दूसरी ओर, यदि गोलाई मोड हमेशा शून्य की ओर है, तो आपको वह परिणाम मिलता है जिसकी आप अपेक्षा कर रहे थे।

#include <cfenv>अपने कोड में जोड़ने और निम्न पंक्ति का प्रयास करें ।

fesetround(FE_TOWARDZERO);

यह किसी भी राशि को बीच 1.0- बीच में सख्ती 1 + epsilonसे पेश करता है 1.0। अब आपको मशीन एप्सिलॉन को व्यवहार करते हुए देखना चाहिए जैसा कि आपने अपेक्षा की थी।

अन्य गारंटीकृत गोलाई मोड -infinity और + infinity की ओर हैं। देखें cppreference.com जानकारी के लिए।