C # में पूर्णांक विभाजन एक पूर्णांक क्यों लौटाता है और फ्लोट नहीं है?


131

क्या किसी को पता है कि C # में पूर्णांक विभाजन एक पूर्णांक क्यों देता है और फ्लोट नहीं है? इसके पीछे क्या विचार है? (क्या यह केवल C / C ++ की विरासत है?)

C # में:

float x = 13 / 4;   
//== operator is overridden here to use epsilon compare
if (x == 3.0)
   print 'Hello world';

इस कोड का परिणाम होगा:

'Hello world'

स्पष्ट रूप से, पूर्णांक विभाजन जैसी कोई चीज नहीं होती है (परिभाषा के अनुसार विभाजन एक ऑपरेशन है जो एक परिमेय संख्या का उत्पादन करता है, पूर्णांक बहुत छोटे उपसमूह हैं।)


46
क्योंकि यह integerविभाजन नहीं floating pointविभाजन है।
हंटर मैकमिलन

यह (VB.Net में) इसे एक प्राकृतिक गणितीय तरीके से अलग तरीके से लागू किया जाता है जहां विभाजन ऑपरेशन के सभी परिणाम एक अपरिमेय संख्या है।
बैंडिटो बन्नी

3
मुझे लगता है कि आप तर्कसंगत संख्याओं से मतलब रखते हैं । विकिपीडिया देखें : दो पूर्णांक विभाजित करने पर परिणाम शेष हो सकता है। शेष के विभाजन को पूरा करने के लिए, संख्या प्रणाली को भिन्न या तर्कसंगत संख्याओं को शामिल करने के लिए विस्तारित किया जाता है क्योंकि वे आमतौर पर अधिक कहलाते हैं।
दुर्घटनाग्रस्त

6
यही कारण है कि मैं भाषाओं में "नकल सिंटैक्स" का प्रशंसक नहीं हूं। मैं सोचता हूँ VB से आता है "C # .NET है" नहीं "C # C की तरह है"। मेरी गलती का मैं अनुमान लगाता हूं, लेकिन इस मामले में मैं वीबी तरीका पसंद करता हूं। यदि वे बिना संकलित सरल प्रकारों का उपयोग करते हुए एक कंपाइलर त्रुटि उत्पन्न करने की परेशानी से गुज़रते हैं (आपको सी में चेतावनी भी नहीं मिलती है) तो फ़्लोट में पूर्णांक विभाजन को असाइन करते समय आपको चेतावनी क्यों नहीं दी जाती है?
दर्दा

जवाबों:


96

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

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

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

इन (और अन्य संबंधित) कारणों के कारण, पूर्णांक विभाजन के परिणामस्वरूप पूर्णांक होता है। यदि आप दो पूर्णांकों के फ़्लोटिंग पॉइंट डिवीज़न को प्राप्त करना चाहते हैं, तो आपको बस एक double/ float/ को कास्ट करना याद रखना होगा decimal


5
VB.Net .net में आर्किटेक्ट्स ने एक और निर्णय लिया: / - हमेशा एक फ्लोट डिवीजन, \ - पूर्णांक डिवीजन, इसलिए यह असंगत की तरह है, सिवाय अगर आप सी ++ विरासत पर विचार करते हैं;
बैंडिटबनी

4
आप निर्धारित कर सकते हैं, संकलित समय पर, क्या /ऑपरेटर पूर्णांक या फ्लोटिंग पॉइंट डिवीज़न का प्रदर्शन करेगा (जब तक कि आप गतिशील का उपयोग नहीं कर रहे हैं)। अगर आपके लिए यह पता लगाना मुश्किल है कि आप उस एक लाइन पर इतना काम कर रहे हैं, तो मैं उस लाइन को कई लाइनों में तोड़ने का सुझाव दूंगा ताकि यह पता लगाना आसान हो जाए कि ऑपरेंड पूर्णांक हैं या फ्लोटिंग पॉइंट प्रकार। भविष्य में आपके कोड के पाठक इसकी सराहना करेंगे।
सेवाकाल

5
मुझे व्यक्तिगत रूप से यह समस्याग्रस्त लगता है कि मुझे हमेशा यह सोचना पड़ता है कि मैं किस चर को विभाजित कर रहा हूं, मैं इसे अपने ध्यान के बेकार उपयोग के रूप में गिनता हूं।
BanditoBunny

8
@pelesl जैसा कि यह एक बहुत बड़ा ब्रेकिंग परिवर्तन होगा , जिसके लिए एक खगोलीय संख्या के कार्यक्रमों को तोड़ा जाएगा, मैं पूरे विश्वास के साथ कह सकता हूं कि यह C # में कभी नहीं होगा। यह उस तरह की चीज है जिसे एक भाषा में दिन 1 से किया जाना चाहिए या बिल्कुल नहीं।
सेविला

2
@ सरवी: सी, सी ++, और सी # में बहुत सारी चीजें हैं। व्यक्तिगत रूप से, मुझे लगता है कि सी # एक बेहतर भाषा होगी यदि पूर्णांक विभाजन के लिए एक अलग ऑपरेटर था और, वैध कोड उपज आश्चर्यजनक व्यवहार से बचने के लिए, int/intऑपरेटर बस अवैध थे [एक नैदानिक ​​निर्दिष्ट के साथ कि कोड को एक ऑपरेंड डालना होगा या उपयोग करना चाहिए अन्य ऑपरेटर, जिसके आधार पर व्यवहार वांछित था]। पूर्णांक विभाजन के लिए कुछ अन्य अच्छे टोकन अनुक्रम उपलब्ध थे, यह /उस उद्देश्य के लिए उपयोग को चित्रित करना संभव हो सकता है , लेकिन मुझे नहीं पता कि क्या व्यावहारिक होगा।
सुपरकैट

77

सी # विनिर्देश देखें । डिवीजन ऑपरेटर तीन प्रकार के होते हैं

  • पूर्णांक विभाजन
  • फ्लोटिंग-पॉइंट डिवीजन
  • दशम मंडल

आपके मामले में हमारे पास इंटेगर डिवीजन है, जिसमें निम्नलिखित नियम लागू हैं:

विभाजन परिणाम को शून्य की ओर ले जाता है, और परिणाम का निरपेक्ष मान सबसे बड़ा संभव पूर्णांक होता है जो दो ऑपरेंड के भागफल के निरपेक्ष मान से कम होता है। परिणाम शून्य या सकारात्मक होता है जब दो ऑपरेंड के समान संकेत और शून्य या नकारात्मक होते हैं जब दोनों ऑपरेंड के विपरीत संकेत होते हैं।

मुझे लगता है कि इसका कारण यह है कि C # पूर्णांक के लिए इस प्रकार के विभाजन का उपयोग करता है (कुछ भाषाएं फ्लोटिंग परिणाम लौटाती हैं) हार्डवेयर - पूर्णांक विभाजन तेज और सरल है।


कौन सी भाषाएं लौटाती हैं परिणाम? @SergeyBerezovskiy
इलारिया

40

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

int x = 13;
int y = 4;
float x = (float)y / (float)z;

या, यदि आप शाब्दिक उपयोग कर रहे हैं:

float x = 13f / 4f;

ध्यान रखें, फ्लोटिंग पॉइंट सटीक नहीं हैं। यदि आप सटीकता की परवाह करते हैं, तो इसके बजाय दशमलव प्रकार की तरह कुछ का उपयोग करें।


1
+1 यह उल्लेख करने के लिए कि फ्लोटिंग पॉइंट डिवीजन बनाने के लिए केवल एक शब्द को फ्लोट करने की आवश्यकता है।
Xynariz

स्पष्ट रूप से सटीकता के बारे में आपका कथन सीखने के संदर्भ में और इसे समझने के लिए जटिल नहीं बनाने का अधिकार है। जैसा कि हमें अपनी नौकरियों में जितना संभव हो उतना सटीक होना चाहिए, मैं अभी भी सटीक पर स्पष्ट करना चाहता हूं: IEE 754-1985 के अनुसार आप एक सटीक परिणाम प्राप्त कर सकते हैं (भले ही यह ज्यादातर ऐसा नहीं हो)। आप एक सटीक परिणाम प्राप्त कर सकते हैं, जब गणना मूल्यों को पहले सटीक रूप से प्रस्तुत किया गया है और परिणाम है - बस बोल रहा है - 2. की शक्तियों का एक योग। भले ही उन विशेष मामलों में उस सटीकता पर भरोसा करना सबसे अच्छा अभ्यास नहीं हो सकता है।
एल। मोंटी

परिशुद्धता पर जोड़: सटीक परिणाम प्राप्त करने की प्रवृत्ति में अत्यधिक सुधार होता है क्योंकि परिणाम 1 या -1 के करीब है। यह थोड़ा भ्रमित हो सकता है कि यह प्रसार अभी भी 0 बना हुआ है क्योंकि अनंत संख्या और परिणाम की एक सीमित संख्या है, जो बिल्कुल प्रस्तुत की जा सकती है। :)
एल। मोंटी

1
@ L.Monty कि ऊपर लाने के लिए धन्यवाद। मैंने इस उत्तर को लिखने के बाद से चल रहे बिंदुओं के बारे में अधिक सीखा है और आप जो बिंदु बना रहे हैं वह उचित है। तकनीकी रूप से, मैं अभी भी कहूंगा कि मेरा कथन "फ्लोटिंग पॉइंट्स सटीक नहीं हैं" स्वीकार्य है, इस अर्थ में कि क्योंकि कुछ सटीक हो सकता है कभी-कभी इसका मतलब यह नहीं है, एक पूरे के रूप में, सटीक है। जैसा कि वे कहते हैं, एक टूटी हुई घड़ी दिन में दो बार सही है, लेकिन मैं कभी भी एक सटीक उपकरण नहीं कहूंगा। मैं वास्तव में नहीं बल्कि हैरान कर रहा हूँ बात यह है कि आप मेरे सुझाव है कि दशमलव प्रकार की तुलना में अधिक परेशान है कि है सटीक।
स्टीवन डॉगगार्ट

दशमलव आवेग हैं, सभी समान कारणों के लिए जो तैरते हैं; यह सिर्फ इतना है कि फ्लोट बेस -2 हैं और डेसीमल बेस -10 हैं। उदाहरण के लिए, एक दशमलव प्रकार 1/3 का सटीक मान नहीं रख सकता है।
स्टीवन डॉगगार्ट

11

चूँकि आप किसी भी प्रत्यय का उपयोग नहीं करते हैं, शाब्दिक 13और 4पूर्णांक के रूप में व्याख्या की जाती है:

गाइड :

शाब्दिक कोई प्रत्यय है, यह इन प्रकार जिसमें अपने मूल्य दर्शाया जा सकता है की पहली है: int, uint, long, ulong

इस प्रकार, चूंकि आप 13पूर्णांक घोषित करते हैं , पूर्णांक विभाजन किया जाएगा:

गाइड :

प्रपत्र एक्स / वाई के संचालन के लिए, एक विशेष ऑपरेटर कार्यान्वयन का चयन करने के लिए बाइनरी ऑपरेटर ओवरलोड रिज़ॉल्यूशन लागू किया जाता है। ऑपरेंड चयनित ऑपरेटर के पैरामीटर प्रकारों में परिवर्तित हो जाते हैं, और परिणाम का प्रकार ऑपरेटर का रिटर्न प्रकार होता है।

पूर्वनिर्धारित डिवीजन ऑपरेटरों को नीचे सूचीबद्ध किया गया है। ऑपरेटर सभी एक्स और वाई के भागफल की गणना करते हैं।

पूर्णांक विभाजन:

int operator /(int x, int y);
uint operator /(uint x, uint y);
long operator /(long x, long y);
ulong operator /(ulong x, ulong y);

और इसलिए नीचे चक्कर लगाना होता है:

विभाजन परिणाम को शून्य की ओर ले जाता है, और परिणाम का निरपेक्ष मान सबसे बड़ा संभव पूर्णांक होता है जो दो ऑपरेंड के भागफल के निरपेक्ष मान से कम होता है। परिणाम शून्य या सकारात्मक होता है जब दो ऑपरेंड के समान संकेत और शून्य या नकारात्मक होते हैं जब दोनों ऑपरेंड के विपरीत संकेत होते हैं।

यदि आप निम्न कार्य करते हैं:

int x = 13f / 4f;

आप एक संकलक त्रुटि प्राप्त करेंगे, चूंकि एक फ़्लोटिंग-पॉइंट डिवीजन (के /ऑपरेटर)13f ) एक फ्लोट में परिणाम देता है, जिसे अंतर्निहित रूप से इंट करने के लिए नहीं डाला जा सकता है।

यदि आप चाहते हैं कि विभाजन एक फ़्लोटिंग-पॉइंट डिवीज़न हो, तो आपको परिणाम को फ़्लोट करना होगा:

float x = 13 / 4;

ध्यान दें कि आप अभी भी पूर्णांकों को विभाजित करेंगे, जो स्पष्ट रूप से फ्लोट करने के लिए डाली जाएगी: परिणाम होगा 3.0fप्रत्यय ( 13f, 4f) का उपयोग करते हुए स्पष्ट रूप से ऑपरेंड को फ्लोट के रूप में घोषित करने के लिए ।


+1 यह समझाने के लिए कि आपके पास एक फ़्लोट के रूप में उत्तर हो सकता है लेकिन फिर भी पूर्णांक विभाजन करते हैं। इसके अतिरिक्त, मैंने फ्लोटिंग पॉइंट डिवीजन को मजबूर करने के लिए एक और सामान्य तरीका देखा है कि डिवीजन के पहले कार्यकाल को गुणा करना है 1.0
Xynariz

8

इसका सिर्फ एक बुनियादी ऑपरेशन है

याद रखें जब आपने विभाजन करना सीखा था। शुरुआत में हमने हल किया 9/6 = 1 with remainder 3

9 / 6 == 1  //true
9 % 6 == 3 // true

उन मूल्यों को पुनः प्राप्त करने के लिए% -ओपरेटर के साथ संयोजन में / -ऑपरेटर का उपयोग किया जाता है।


6

उपयोगी हो सकता है:

double a = 5.0/2.0;   
Console.WriteLine (a);      // 2.5

double b = 5/2;   
Console.WriteLine (b);      // 2

int c = 5/2;   
Console.WriteLine (c);      // 2

double d = 5f/2f;   
Console.WriteLine (d);      // 2.5

कृपया अपने उत्तर के लिए कुछ स्पष्टीकरण जोड़ने का प्रयास करें
NetStarter

अंतिम अभिव्यक्ति का उत्पादन होगा 2.5, नहीं 2
लास वी। कार्लसन

हां, गुमराह करना। धन्यवाद।
eozten

4

परिणाम हमेशा प्रकार का होगा जिसमें अंश और हर का अधिक से अधिक भाग होता है। अपवाद बाइट और शॉर्ट हैं, जो int (Int32) का उत्पादन करते हैं।

var a = (byte)5 / (byte)2;  // 2 (Int32)
var b = (short)5 / (byte)2; // 2 (Int32)
var c = 5 / 2;              // 2 (Int32)
var d = 5 / 2U;             // 2 (UInt32)
var e = 5L / 2U;            // 2 (Int64)
var f = 5L / 2UL;           // 2 (UInt64)
var g = 5F / 2UL;           // 2.5 (Single/float)
var h = 5F / 2D;            // 2.5 (Double)
var i = 5.0 / 2F;           // 2.5 (Double)
var j = 5M / 2;             // 2.5 (Decimal)
var k = 5M / 2F;            // Not allowed

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

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