बहुत सारे (पुराने) प्रोग्राम राउंड (इनपुट) के बजाय फ्लोर (0.5 + इनपुट) का उपयोग क्यों करते हैं?


80

मेरे द्वारा दिए गए टाई-ब्रेकिंग के आस-पास के इनपुट्स के अंतर को लौटाते हैं, जैसे कि मैं इस कोड को मानता हूं :

int main()
{
    std::cout.precision(100);

    double input = std::nextafter(0.05, 0.0) / 0.1;
    double x1 = floor(0.5 + input);
    double x2 = round(input);

    std::cout << x1 << std::endl;
    std::cout << x2 << std::endl;
}

कौन से आउटपुट:

1
0

लेकिन वे अंत में सिर्फ अलग-अलग परिणाम हैं, एक अपने पसंदीदा को चुनता है। मैं का उपयोग कर "पुराने" C / C ++ कार्यक्रमों के बहुत सारे देख floor(0.5 + input)के बजाय round(input)

क्या कोई ऐतिहासिक कारण है? सीपीयू पर सबसे सस्ता?


20
एसटीडी :: गोल आधे मामलों को शून्य से दूर ले जाता है। यह गणितीय रूप से एक समान नहीं है, जैसे कि फर्श (f +। 5), जहां आधे रास्ते हमेशा ऊपरी तरफ जाते हैं। फर्श विधि का उपयोग करने का कारण यह है कि यह इंजीनियरिंग की दुनिया में उचित गोलाई के लिए आवश्यक है।
माइकल रॉय

7
जैसा कि राउंड में बताया गया है () C ++ प्री-सी ++ 11 में फ्लोट के लिए हमारे पास राउंड नहीं था। जैसा कि मैंने अपने उत्तर में लिखा है कि अपना दौर सही ढंग से लिखना एक कठिन समस्या है।
शाफिक याघमौर

16
@Arne का उपयोग std :: दौर () -0.5 और +0.5 के गोल मूल्यों के बीच की दूरी है। 2. फर्श का उपयोग करना, यह 1. केवल तब होता है जब दो मूल्यों के विपरीत संकेत होते हैं। बहुत परेशान जब सीधी रेखा खींचने की कोशिश कर रहा है, या आप गलत बनावट पिक्सेल उठाते हैं।
माइकल रॉय

20
कुछ प्रोग्रामिंग भाषा और वातावरण (.NET सहित) बैंकर के राउंडिंग नामक एक धोखा देने वाली चीज़ का उपयोग करते हैं, जिसमें निकटतम ईवीआर नंबर पर x.5 राउंड होता है। तो 0.5 राउंड टू 0 जबकि 1.5 राउंड टू 2. आप डिबगिंग के कारण होने वाले भ्रम की कल्पना कर सकते हैं। मुझे लगता है कि इस बुराई 'सुविधा' का समाधान एक .Round () फ़ंक्शन बिल्कुल नहीं है, और इसके बजाय .RoundBankers (), .RoundHalfUp (), .RoundHalfDown (), आदि (या .BankersRound) (), आदि। लेकिन intellisense .RoundBankers ()) के साथ बेहतर काम करेगा। कम से कम उस तरह से आप यह जानने के लिए मजबूर होंगे कि क्या करना है।
user3685427

8
@ user3685427: वित्तीय और सांख्यिकीय अनुप्रयोगों में बैंकर की राउंडिंग आवश्यक है जो शून्य राउंडिंग से दूर पेश किए गए सूक्ष्म और प्रणालीगत ऊर्ध्व पूर्वाग्रह के उन्मूलन की आवश्यकता है । हार्डवेयर फ्लोटिंग पॉइंट कार्यान्वयन के वास्तविक ज्ञान के बिना इसे लागू करना लगभग असंभव है, इसलिए यह सी # में डिफ़ॉल्ट के रूप में चयन है।
पीटर गेकरेंस ने

जवाबों:


115

std::roundC ++ 11 में पेश किया गया है। इससे पहले, केवल std::floorउपलब्ध था इसलिए प्रोग्रामर इसका उपयोग कर रहे थे।


कुछ भी तो नहीं। लेकिन इसका सी ++ 11 से अधिक पुराना है। मैंने सोचा कि सी ++ 11 से पहले मिल गया है। यह सब है;)
मार्कज

12
@markzzz - C ++ मानक पुस्तकालय स्वचालित रूप से C की मानक लाइब्रेरी को इनहेरिट नहीं करता है। वहाँ चुनने और चुनने में सावधानी बरती जा रही है। C99 को सिंक करने में उन्हें 12 साल लग गए।
स्टोरीटेलर - Unslander Monica

2
@ झटके: वास्तव में। IMHO C C ++ 11 तक गणितीय कार्यों के मामले में C ++ से आगे था।
बथशेबा

3
यह ध्यान रखना महत्वपूर्ण है कि उपयोग की जा रही विधि कुछ इनपुट के लिए टूट जाती है और यह भी कि C ++ 11 C99 पर निर्भर करता है जबकि C ++ 03 C90 पर निर्भर करता है जो @markzzz बिंदु पर जाता है।
शाफिक याघमौर

1
@markzzz: आपकी टिप्पणी (आलोचकों के बावजूद) हाजिर है। बात यह है कि, C ++ मानकों के बिना एक लंबा अंतराल था, पहला C ++ मानक C ++ 98 था और पहला बड़ा संशोधन ++ 11 था। एक मामूली अपडेट था, C ++ 03, लेकिन विकिपीडिया पृष्ठ के नोटों के अनुसार यह ज्यादातर "बग फिक्स" था। इसलिए, सी ++ 11 सी मानक पुस्तकालय को पकड़ने का पहला अवसर था, 13 साल के आईटस के बाद।
Matthieu M.

21

कोई ऐतिहासिक कारण नहीं है। इस तरह का विचलन वर्ष डॉट के बाद से है। लोक ऐसा तब करते हैं जब वे बहुत, बहुत शरारती महसूस कर रहे होते हैं। यह फ्लोटिंग पॉइंट अंकगणित का दुरुपयोग है, और कई अनुभवी पेशेवर प्रोग्रामर इसके लिए आते हैं। यहां तक ​​कि जावा बॉड्स ने संस्करण 1.7 तक किया। मजाकिया लड़के।

मेरा अनुमान है कि सी -11 (C99 C में अपने होने के बावजूद) तक एक अच्छा आउट-ऑफ-द-बॉक्स जर्मन राउंडिंग फ़ंक्शन औपचारिक रूप से उपलब्ध नहीं था, लेकिन यह वास्तव में तथाकथित विकल्प को अपनाने के लिए कोई बहाना नहीं है।

यहाँ बात है: floor(0.5 + input) हमेशा इसी std::roundकॉल के रूप में एक ही परिणाम ठीक नहीं है !

कारण काफी सूक्ष्म है: a.5एक पूर्णांक के लिए एक जर्मन गोलाई के लिए कटऑफ बिंदु a, ब्रह्मांड की एक संयोग संपत्ति, एक रंगादिक तर्कसंगत है । जैसा कि यह IEEE754 में 2 के 52 वें पावर तक फ्लोटिंग पॉइंट के रूप में दर्शाया जा सकता है, और इसके बाद राउंडिंग वैसे भी नो-ऑप है, std::roundहमेशा ठीक से काम करता है। अन्य फ़्लोटिंग पॉइंट योजनाओं के लिए, दस्तावेज़ से परामर्श करें।

लेकिन कैन 0.5को जोड़ने से doubleकुछ मूल्यों के लिए थोड़ी सी भी कमी हो सकती है। यदि आप इसके बारे में सोचते हैं, तो दो doubleमूल्यों को एक साथ जोड़ते हैं - जो कि अस्वाभाविक इनकार रूपांतरण की स्थापना है - और एक फ़ंक्शन लागू करना जो इनपुट का एक बहुत मजबूत कार्य है (जैसे कि एक राउंडिंग फ़ंक्शन), आँसू में समाप्त होने के लिए बाध्य है।

यह मत करो

संदर्भ: Math.round (0.49999999999999994) 1 क्यों आता है?


2
टिप्पणियाँ विस्तारित चर्चा के लिए नहीं हैं; इस वार्तालाप को बातचीत में स्थानांतरित कर दिया गया है ।
एंडी

2
nearbyint()आमतौर पर एक बेहतर विकल्प है round(), क्योंकि nearbyintफंकी टाईब्रेक के बजाय वर्तमान राउंडिंग मोड का उपयोग शून्य से दूर है round()(जिसमें x86 के लिए हार्डवेयर समर्थन भी नहीं है, हालांकि एआरएम करता है)। दोनों को C ++ 11 में C ++ में जोड़ा गया था।
पीटर कॉर्डेस

9

मुझे लगता है कि यह वह जगह है जहाँ आप गलत करते हैं:

लेकिन वे अंत में सिर्फ अलग-अलग परिणाम हैं, एक अपने पसंदीदा को चुनता है। मैं दौर (इनपुट) के बजाय फर्श (0.5 + इनपुट) का उपयोग करके बहुत सारे "पुराने" सी / सी ++ प्रोग्राम देखता हूं।

बात वह नहीं है। आपको डोमेन के लिए सही गोलाई योजना का चयन करना होगा । एक वित्तीय अनुप्रयोग में, आप बैंकर के नियमों का उपयोग करके गोल करेंगे (वैसे फ्लोट का उपयोग नहीं करते)। जब नमूना, हालांकि, static_cast<int>(floor(f + .5))पैदावार कम नमूना शोर का उपयोग कर , यह गतिशील रेंज बढ़ाता है। जब पिक्सल को संरेखित करते हैं, अर्थात किसी स्थिति को स्क्रीन निर्देशांक में परिवर्तित करते हैं, तो किसी अन्य गोलाई पद्धति का उपयोग करके छेद, अंतराल और अन्य कलाकृतियों का उत्पादन होगा।


"यह गतिशील सीमा को बढ़ाता है" - अर्थहीन अतिरिक्त पाठ जैसा दिखता है; कहीं से गलती से कॉपी-पेस्ट तो नहीं हो गया? इसे हटाना चाह सकते हैं।
अनातोलीग

नहीं। नमूना के शोर को कम करने से शोर मंजिल कम हो जाता है और यह वास्तव में गतिशील सीमा को बढ़ाता है।
मिशैल रॉय

क्या आप एक सरल उदाहरण या एक संदर्भ प्रदान कर सकते हैं जो गतिशील रेंज / शोर में कमी की वृद्धि को दर्शाता है?
रुस्लान

1
मानक पूर्णांक (राउंडिंग की कमी) के साथ, शून्य और माइनस वन के बीच सभी मान "गायब" हो जाते हैं, या साइन (समान मान और 0 से + 1 इनपुट के लिए) बदल जाते हैं, सभी नकारात्मक मान कम से कम एक बिट से ऑफसेट होते हैं। यहाँ एक शोर के साथ आसवन जोड़ा गया है।
माइकल रॉय

4

एक सरल कारण यह हो सकता है कि राउंडिंग नंबरों के अलग-अलग तरीके हैं, जब तक कि आप उपयोग की गई विधि को नहीं जानते, आप अलग-अलग परिणाम प्राप्त कर सकते हैं।

मंजिल () के साथ, आप परिणामों के अनुरूप हो सकते हैं। यदि फ्लोट .5 या अधिक है, तो इसे जोड़ना अगले इंट तक टकराएगा। लेकिन .49999 केवल दशमलव को छोड़ देगा।


+1 इस जवाब का बिंदु इस सवाल पर की गई टिप्पणियों से बना है, जिसमें इस बारे में असहमति है कि क्या round()होता है।
लादुविज्क

@Aaron जवाब गलत floor(x + 0.5)है, हालांकि क्या करता है।
ईओएफ

ओह, हा! अच्छी पकड़ है। यह विडंबना है। "बेहतर ज्ञात एक्स का उपयोग करें क्योंकि हम समझौते में नहीं हैं या वाई के बारे में पूर्ण ज्ञान नहीं है।" तो जब आप X पर लागू होते हैं तो आप क्या करते हैं?
Loduwijk

1
@ ऐरन आसान। आप केवल एक ही चीज़ करते हैं और उपयोग करते हैं nearbyint(x), जो (पास भी समीप) राउंडिंग का उपयोग करता है, बशर्ते आपने फ़्लोटिंग पॉइंट वातावरण के साथ खिलवाड़ न किया हो।
EOF

@ ईओएफ: आपकी गोलाई पसंद समझदार नहीं है। एक गोल फ़ंक्शन जो नॉनलाइनियर घटक में अवधि 1 नहीं है, पागल है।
एरिक टावर्स

2

कई प्रोग्रामर उन मुहावरों को अपनाते हैं जो उन्होंने अन्य भाषाओं के साथ प्रोग्रामिंग करते समय सीखे थे। सभी भाषाओं में round()फ़ंक्शन नहीं होता है, और उन भाषाओं floor(x + 0.5)में विकल्प के रूप में उपयोग करना सामान्य है । जब ये प्रोग्रामर C ++ का उपयोग करना शुरू करते हैं, तो उन्हें हमेशा यह एहसास नहीं होता है कि वहाँ एक अंतर्निहित है round(), वे उस शैली का उपयोग करना जारी रखते हैं जिसका वे उपयोग कर रहे हैं।

दूसरे शब्दों में, सिर्फ इसलिए कि आप बहुत सारे कोड देखते हैं जो कुछ करता है, इसका मतलब यह नहीं है कि ऐसा करने का एक अच्छा कारण है। इसका उदाहरण आप हर प्रोग्रामिंग लैंग्वेज में पा सकते हैं। स्टर्जन के नियम याद रखें :

नब्बे प्रतिशत सब कुछ बकवास है

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.