क्यों num_limits मशीन एप्सिलॉन 1 + ई> 1 स्थिति को संतुष्ट नहीं करता है?
अगर मैं गलत नहीं हूँ मशीन 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
क्या मैं किसी दिन यहां गायब हूं?
जवाब
यदि मैं गलत नहीं हूँ तो मशीन एप्सिलॉन की परिभाषा सबसे कम संख्या है जो स्थिति को संतुष्ट करती है: [
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 जानकारी के लिए।