मैं यह सुनिश्चित करना चाहता हूं कि यदि आवश्यक हो तो पूर्णांकों का एक विभाजन हमेशा गोल हो। क्या इससे बेहतर कोई तरीका है? काफी कास्टिंग चल रही है। :-)
(int)Math.Ceiling((double)myInt1 / myInt2)
मैं यह सुनिश्चित करना चाहता हूं कि यदि आवश्यक हो तो पूर्णांकों का एक विभाजन हमेशा गोल हो। क्या इससे बेहतर कोई तरीका है? काफी कास्टिंग चल रही है। :-)
(int)Math.Ceiling((double)myInt1 / myInt2)
जवाबों:
अद्यतन: यह प्रश्न जनवरी 2013 में मेरे ब्लॉग का विषय था । महान प्रश्न के लिए धन्यवाद!
पूर्णांक अंकगणितीय सही होना कठिन है। जैसा कि इस प्रकार अब तक प्रदर्शित किया गया है, जिस क्षण आप "चतुर" चाल करने की कोशिश करते हैं, संभावनाएं अच्छी होती हैं कि आपने गलती की है। और जब कोई दोष पाया जाता है, तो यह तय किए बिना कि क्या कुछ और टूट जाता है, एक अच्छी समस्या को सुलझाने की तकनीक नहीं है, इस पर विचार किए बिना दोष को ठीक करने के लिए कोड को बदलना । अब तक हमने सोचा है कि यह पूरी तरह से विशेष रूप से मुश्किल समस्या पोस्ट करने के लिए पांच अलग-अलग गलत पूर्णांक अंकगणितीय समाधान हैं।
पूर्णांक अंकगणितीय समस्याओं के दृष्टिकोण का सही तरीका - वह तरीका, जो पहली बार में उत्तर प्राप्त करने की संभावना को बढ़ाता है - समस्या को सावधानी से दृष्टिकोण करना है, इसे एक बार में एक कदम हल करें, और करने में अच्छे इंजीनियरिंग सिद्धांतों का उपयोग करें इसलिए।
जिसे आप बदलने का प्रयास कर रहे हैं, उसके लिए विनिर्देश पढ़कर शुरू करें। पूर्णांक विभाजन के लिए विनिर्देश स्पष्ट रूप से बताता है:
विभाजन परिणाम को शून्य की ओर ले जाता है
परिणाम शून्य या सकारात्मक होता है जब दो ऑपरेंड के समान संकेत और शून्य या नकारात्मक होते हैं जब दोनों ऑपरेंड के विपरीत संकेत होते हैं
यदि बाएं ऑपरेंड सबसे छोटा प्रतिनिधित्व योग्य इंट और राइट ऑपरैंड -1 है, तो एक अतिप्रवाह होता है। [...] यह कार्यान्वयन के रूप में परिभाषित किया जाता है कि क्या [एक अंकगणित अपवाद] फेंक दिया जाता है या ओवरफ्लो चला जाता है जिसके परिणामस्वरूप मूल्य बाएं ऑपरेंड के समान होता है।
यदि सही ऑपरेंड का मान शून्य है, तो System.DivideByZeroException को फेंक दिया जाता है।
हम जो चाहते हैं वह पूर्णांक विभाजन फ़ंक्शन है जो भागफल की गणना करता है लेकिन परिणाम हमेशा ऊपर की ओर होता है , हमेशा शून्य की ओर नहीं ।
इसलिए उस फ़ंक्शन के लिए एक विनिर्देश लिखें। हमारे कार्य में int DivRoundUp(int dividend, int divisor)
हर संभव इनपुट के लिए परिभाषित व्यवहार होना चाहिए। यह अपरिभाषित व्यवहार गहरी चिंताजनक है, तो चलिए इसे खत्म करते हैं। हम कहेंगे कि हमारे ऑपरेशन में यह विनिर्देश है:
यदि विभाजक शून्य है तो ऑपरेशन फेंकता है
यदि लाभांश int.minval है और भाजक -1 है, तो ऑपरेशन फेंकता है
यदि कोई शेष नहीं है - विभाजन 'सम' है - तो वापसी मूल्य अभिन्न भागफल है
अन्यथा यह सबसे छोटा पूर्णांक देता है जो भागफल से अधिक होता है, अर्थात यह हमेशा गोल होता है।
अब हमारे पास एक विनिर्देश है, इसलिए हम जानते हैं कि हम एक परीक्षण योग्य डिजाइन के साथ आ सकते हैं । मान लें कि हम एक अतिरिक्त डिजाइन मानदंड जोड़ते हैं कि समस्या को पूर्णांक अंकगणित के साथ हल किया जा सकता है, बल्कि भागफल को दोहरे के रूप में गणना करने के बजाय, क्योंकि समस्या कथन में "डबल" समाधान स्पष्ट रूप से अस्वीकार कर दिया गया है।
तो हमें क्या गणना करनी चाहिए? स्पष्ट रूप से, पूर्णांक अंकगणित में पूरी तरह से शेष रहते हुए हमारी कल्पना को पूरा करने के लिए, हमें तीन तथ्यों को जानना होगा। सबसे पहले, पूर्णांक भागफल क्या था? दूसरा, क्या विभाजन शेष था? और तीसरा, यदि नहीं, तो पूर्णांक को ऊपर या नीचे गोल करके गणना की गई थी?
अब जब हमारे पास एक विनिर्देश और एक डिज़ाइन है, तो हम कोड लिखना शुरू कर सकते हैं।
public static int DivRoundUp(int dividend, int divisor)
{
if (divisor == 0 ) throw ...
if (divisor == -1 && dividend == Int32.MinValue) throw ...
int roundedTowardsZeroQuotient = dividend / divisor;
bool dividedEvenly = (dividend % divisor) == 0;
if (dividedEvenly)
return roundedTowardsZeroQuotient;
// At this point we know that divisor was not zero
// (because we would have thrown) and we know that
// dividend was not zero (because there would have been no remainder)
// Therefore both are non-zero. Either they are of the same sign,
// or opposite signs. If they're of opposite sign then we rounded
// UP towards zero so we're done. If they're of the same sign then
// we rounded DOWN towards zero, so we need to add one.
bool wasRoundedDown = ((divisor > 0) == (dividend > 0));
if (wasRoundedDown)
return roundedTowardsZeroQuotient + 1;
else
return roundedTowardsZeroQuotient;
}
क्या यह चतुर है? कोई सुंदर नहीं? नहीं लघु? विनिर्देश के अनुसार सही नहीं है? मैं ऐसा मानता हूं, लेकिन मैंने इसका पूरी तरह से परीक्षण नहीं किया है। हालांकि यह बहुत अच्छा लग रहा है।
हम यहाँ पेशेवर हैं; अच्छी इंजीनियरिंग प्रथाओं का उपयोग करें। अपने टूल पर शोध करें, वांछित व्यवहार निर्दिष्ट करें, पहले त्रुटि के मामलों पर विचार करें, और इसकी स्पष्ट शुद्धता पर जोर देने के लिए कोड लिखें। और जब आप एक बग ढूंढते हैं, तो विचार करें कि क्या आपका एल्गोरिदम आपके साथ शुरू होने से पहले ही बेतरतीब ढंग से तुलना करना शुरू कर देता है, ताकि तुलनात्मक रूप से चारों ओर की दिशाओं की अदला-बदली शुरू हो जाए और जो सामान पहले से काम करता है उसे तोड़ दें।
यहाँ अब तक के सभी उत्तर अधिक जटिल प्रतीत होते हैं।
सकारात्मक लाभांश और भाजक के लिए C # और Java में, आपको बस करने की आवश्यकता है:
( dividend + divisor - 1 ) / divisor
((13-1)%3)+1)
परिणाम के रूप में 1 देता है। सही प्रकार के विभाजन को लेना, 1+(dividend - 1)/divisor
सकारात्मक लाभांश और भाजक के उत्तर के समान परिणाम देता है। इसके अलावा, कोई अतिप्रवाह समस्या नहीं है, हालांकि वे कृत्रिम हो सकते हैं।
हस्ताक्षरित पूर्णांकों के लिए:
int div = a / b;
if (((a ^ b) >= 0) && (a % b != 0))
div++;
अहस्ताक्षरित पूर्णांक के लिए:
int div = a / b;
if (a % b != 0)
div++;
पूर्णांक विभाजन ' /
' को शून्य की ओर गोल करने के लिए परिभाषित किया गया है (कल्पना का 7.7.2), लेकिन हम गोल करना चाहते हैं। इसका मतलब है कि नकारात्मक उत्तर पहले से ही सही ढंग से गोल हैं, लेकिन सकारात्मक उत्तरों को समायोजित करने की आवश्यकता है।
गैर-शून्य सकारात्मक जवाबों का पता लगाना आसान है, लेकिन उत्तर शून्य थोड़ा पेचीदा है, क्योंकि यह या तो नकारात्मक मान के चक्कर में पड़ सकता है या सकारात्मक के नीचे चक्कर लगा सकता है।
सबसे सुरक्षित शर्त यह पता लगाना है कि जब उत्तर यह जाँच कर सकारात्मक होना चाहिए कि दोनों पूर्णांक समान हैं। पूर्णांक एक्सोर ऑपरेटर '^
दो मूल्यों पर ' का परिणाम होगा 0 साइन-बिट जब यह मामला होता है, जिसका अर्थ है एक गैर-नकारात्मक परिणाम, इसलिए चेक (a ^ b) >= 0
यह निर्धारित करता है कि परिणाम गोल होने से पहले सकारात्मक होना चाहिए था। यह भी ध्यान दें कि अहस्ताक्षरित पूर्णांकों के लिए, प्रत्येक उत्तर स्पष्ट रूप से सकारात्मक है, इसलिए इस चेक को छोड़ा जा सकता है।
एक ही जाँच शेष है कि क्या कोई राउंडिंग हुई है, जिसके लिए a % b != 0
लिए वह काम करेगा।
अंकगणित (पूर्णांक या अन्यथा) लगभग उतना सरल नहीं है जितना लगता है। हर समय ध्यान से सोचने की आवश्यकता है।
इसके अलावा, हालांकि मेरा अंतिम उत्तर शायद 'सरल' या 'स्पष्ट' या शायद 'तेज' के रूप में फ्लोटिंग पॉइंट उत्तरों के रूप में नहीं है, लेकिन यह मेरे लिए एक बहुत मजबूत रिडीमिंग क्वालिटी है; मैंने अब उत्तर के माध्यम से तर्क दिया है, इसलिए मैं वास्तव में निश्चित हूं कि यह सही है (जब तक कि कोई मुझे अन्यथा न बताए - एरिक के निर्देश में आकर्षक नज़र -)।
फ़्लोटिंग पॉइंट उत्तर के बारे में निश्चितता की समान भावना प्राप्त करने के लिए, मुझे इस बारे में अधिक (और संभवतः अधिक जटिल) सोचना होगा कि क्या कोई ऐसी स्थिति है जिसके तहत फ़्लोटिंग पॉइंट सटीक तरीके से मिल सकता है, और क्या Math.Ceiling
शायद करता है 'सिर्फ सही' इनपुट पर कुछ अवांछनीय।
बदलें (ध्यान दें मैं दूसरे की जगह myInt1
के साथ myInt2
, यह सोचते हैं कि आप क्या मतलब था):
(int)Math.Ceiling((double)myInt1 / myInt2)
साथ में:
(myInt1 - 1 + myInt2) / myInt2
एकमात्र चेतावनी यह है कि यदि myInt1 - 1 + myInt2
आप जिस पूर्णांक प्रकार का उपयोग कर रहे हैं, उससे अधिक हो जाता है, तो आपको वह नहीं मिल सकता है जिसकी आप अपेक्षा करते हैं।
कारण यह गलत है : -1000000 और 3999 में -250 देना चाहिए, यह -249 देता है
संपादित करें: इसे
ध्यान में रखते हुए नकारात्मक myInt1
मानों के लिए अन्य पूर्णांक समाधान के समान त्रुटि है , कुछ ऐसा करना आसान हो सकता है:
int rem;
int div = Math.DivRem(myInt1, myInt2, out rem);
if (rem > 0)
div++;
div
केवल पूर्णांक संचालन का उपयोग करने में सही परिणाम देना चाहिए ।
कारण यह गलत है : -1 और -5 को 1 देना चाहिए, यह 0 देता है
EDIT (एक बार और, भावना के साथ):
डिवीजन ऑपरेटर शून्य की ओर चक्कर लगाता है; नकारात्मक परिणामों के लिए यह बिल्कुल सही है, इसलिए केवल गैर-नकारात्मक परिणामों के समायोजन की आवश्यकता है। यह भी ध्यान में रखते हुए कि DivRem
बस /
और %
वैसे भी, चलो कॉल को छोड़ दें (और जब यह आवश्यक न हो तो modulo गणना से बचने के लिए आसान तुलना के साथ शुरू करें):
int div = myInt1 / myInt2;
if ((div >= 0) && (myInt1 % myInt2 != 0))
div++;
कारण यह गलत है : -1 और 5 को 0 देना चाहिए, यह 1 देता है
(अंतिम प्रयास के अपने बचाव में मुझे कभी भी तर्कपूर्ण उत्तर का प्रयास नहीं करना चाहिए था जबकि मेरा दिमाग मुझे बता रहा था कि मुझे प्रति घंटे 2 घंटे हैं)
एक्सटेंशन विधि का उपयोग करने का सही मौका:
public static class Int32Methods
{
public static int DivideByAndRoundUp(this int number, int divideBy)
{
return (int)Math.Ceiling((float)number / (float)divideBy);
}
}
इससे आपका कोड uber पढ़ने योग्य भी हो जाता है:
int result = myInt.DivideByAndRoundUp(4);
आप एक सहायक लिख सकते हैं।
static int DivideRoundUp(int p1, int p2) {
return (int)Math.Ceiling((double)p1 / p2);
}
आप निम्नलिखित की तरह कुछ का उपयोग कर सकते हैं।
a / b + ((Math.Sign(a) * Math.Sign(b) > 0) && (a % b != 0)) ? 1 : 0)
ऊपर दिए गए कुछ उत्तर फ़्लोट का उपयोग करते हैं, यह अक्षम है और वास्तव में आवश्यक नहीं है। अहस्ताक्षरित ints के लिए यह int1 / int2 के लिए एक कुशल उत्तर है:
(int1 == 0) ? 0 : (int1 - 1) / int2 + 1;
साइन की हुई इन्ट्स के लिए यह सही नहीं होगा
यहां सभी समाधानों के साथ समस्या यह है कि उन्हें एक कास्ट की आवश्यकता है या उन्हें एक संख्यात्मक समस्या है। फ्लोटिंग या डबल करने के लिए कास्टिंग हमेशा एक विकल्प होता है, लेकिन हम बेहतर कर सकते हैं।
जब आप @jerryjvl से उत्तर के कोड का उपयोग करते हैं
int div = myInt1 / myInt2;
if ((div >= 0) && (myInt1 % myInt2 != 0))
div++;
एक राउंडिंग त्रुटि है। 1/5 गोल होगा, क्योंकि 1% 5! = 0. लेकिन यह गलत है, क्योंकि गोलाई केवल तब होगी जब आप 1 को 3 के साथ प्रतिस्थापित करते हैं, इसलिए परिणाम 0.6 है। हमें राउंड अप करने का एक तरीका खोजने की आवश्यकता है जब गणना हमें 0.5 से अधिक या उसके बराबर मूल्य दे। ऊपरी उदाहरण में मोडुलो ऑपरेटर के परिणाम में 0 से myInt2-1 तक की सीमा होती है। राउंडिंग तभी होगी जब शेष बंटवारे के 50% से अधिक हो। तो समायोजित कोड इस तरह दिखता है:
int div = myInt1 / myInt2;
if (myInt1 % myInt2 >= myInt2 / 2)
div++;
निश्चित रूप से हमारे पास myInt2 / 2 में भी एक राउंडिंग समस्या है, लेकिन यह परिणाम आपको इस साइट पर अन्य लोगों की तुलना में बेहतर राउंडिंग समाधान देगा।