C ++ पूर्णांक विभाजन और शेष प्राप्त करने का सबसे अच्छा तरीका है


103

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

क्या यह होगा

int c = (int)a / b;
int d = a % b;

या

int c = (int)a / b;
int d = a - b * c;

या

double tmp = a / b;
int c = (int)tmp;
int d = (int)(0.5+(tmp-c)*b);

या

हो सकता है कि कोई जादुई कार्य हो जो एक बार में दोनों को दे दे?


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

2
तीसरा एक बीएड विकल्प है: क्या होगा अगर tmp = 54.99999999999999943157? इसने कहा, पुरानी शैली की कास्टिंग कभी भी एक चतुर चीज नहीं है।
जिमीफिकी

जवाबों:


98

X86 पर शेष भाग विभाजन का एक उप-उत्पाद है, इसलिए किसी भी आधे-सभ्य संकलक को इसका उपयोग करने में सक्षम होना चाहिए (और divफिर से प्रदर्शन नहीं करना चाहिए)। ऐसा शायद दूसरे आर्किटेक्चर पर भी किया जाता है।

निर्देश: DIVsrc

नोट: अनसाइनड डिवीजन। "Src" द्वारा विभक्त संचायक (AX)। यदि भाजक एक बाइट मान है, तो परिणाम को AL में डाल दिया जाता है और AH को शेष कर दिया जाता है । यदि भाजक एक शब्द मान है, तो DX: AX को "src" से विभाजित किया जाता है और परिणाम AX में संग्रहीत किया जाता है और शेष DX में संग्रहीत किया जाता है

int c = (int)a / b;
int d = a % b; /* Likely uses the result of the division. */

9
मुझे लगता है कि प्राथमिक विद्यालय से कई कवि जानते हैं कि विभाजन करते समय आपको शेष राशि मुफ्त में मिलती है। असली सवाल यह है कि क्या इसका फायदा उठाने के लिए हमारे कंपाइलर काफी स्मार्ट हैं?

1
@jdv: मुझे आश्चर्य नहीं होगा। यह एक बहुत ही सरल अनुकूलन है।
जॉन प्यूरी

68
मैंने त्वरित परीक्षण का प्रयास किया। जी ++ 4.3.2 का उपयोग कर -O2 के साथ, कोडांतरक आउटपुट स्पष्ट रूप से एक idivlनिर्देश का उपयोग करके और ईएक्सएक्स और एडेक्स में परिणामों का उपयोग करके दिखाता है। अगर यह नहीं होता तो मैं चौंक जाता।
फ्रेड लार्सन

2
@EuriPinhollow इस बात से सहमत हैं कि यह x86 के बारे में कोई सवाल नहीं है। मैंने केवल इसे एक उदाहरण के रूप में दिया, अत्यधिक संदिग्ध धारणा के साथ कि अन्य आर्किटेक्चर शायद कुछ ऐसा ही करते हैं।
cnicutar

3
आपको कंपाइलर को ऑप्टिमाइज़ करने के लिए बताने की ज़रूरत है, हालाँकि, कम से कम g ++ के लिए। X86_64 पर g ++ 6.3.0 के साथ एक सरल प्रयोग से पता चला कि किसी भी अनुकूलन के साथ, आपको दो idivlनिर्देश मिलते हैं , लेकिन -O1अधिक या अधिक, आपको एक मिलता है। जैसा कि मैनुअल कहता है, "बिना किसी अनुकूलन विकल्प के ... विवरण स्वतंत्र हैं"
टॉम ज़िक

80

std::div परिणाम और शेष दोनों के साथ एक संरचना देता है।


5
मैं यह जानने के लिए उत्सुक हूं कि क्या यह वास्तव में आधुनिक संकलक की तुलना में विकल्प 1 से अधिक कुशल है।
ग्रेग हॉवेल

2
अच्छा लगा, मुझे नहीं पता था। क्या यह तेज है?

अच्छा लगा। क्या आपको पता होगा कि क्या किसी को लंबे समय तक लागू किया जाता है?
कुकी

@Cookie: C ++ 03 की कोई अवधारणा नहीं है long long, लेकिन यह अत्यधिक संभावना है कि आपके संकलक के पास विस्तार long longके std::divरूप में अधिक भार है ।
ildjarn

@Greg: मुझे नहीं लगता कि यह देखते हुए, यह संभवत: स्मृति में एक संरचना के लिए परिणाम लिखने और इसे वापस करने के लिए है, जो (जब तक कि यह इनलाइन के रूप में संकलित नहीं होता है और संरचना की पहुंच को अनुकूलित किया जाता है) एक बड़ा दंड है एक अतिरिक्त विभाजन निर्देश।
Pezcode

28

X86 पर कम से कम, g ++ 4.6.1 बस IDIVL का उपयोग करता है और उस एकल निर्देश से दोनों प्राप्त करता है।

C ++ कोड:

void foo(int a, int b, int* c, int* d)
{
  *c = a / b;
  *d = a % b;
}

x86 कोड:

__Z3fooiiPiS_:
LFB4:
    movq    %rdx, %r8
    movl    %edi, %edx
    movl    %edi, %eax
    sarl    $31, %edx
    idivl   %esi
    movl    %eax, (%r8)
    movl    %edx, (%rcx)
    ret

क्या आदेश मायने रखता है? उदाहरण के लिए यदि आप एक से अधिक पुनरावृत्ति कर रहे हैं /=- तो आपको पहले विभाजन रखने के लिए एक अस्थायी चर का उपयोग करना पड़ सकता है।
अन्नपूर्णे

@ अस्नान यह तब कोई मायने नहीं रखता था, और यह आजकल नहीं है। कंपाइलर इसे फिर से चलाने के लिए काफी स्मार्ट हैं।
साहसाहे

10

नमूना कोड परीक्षण div () और संयुक्त डिवीजन और मॉड। मैंने इन्हें gcc -O3 के साथ संकलित किया, मुझे कंपाइलर को सबकुछ ऑप्टिमाइज़ करने से रोकने के लिए doNothing पर कॉल जोड़ना पड़ा (आउटपुट + मॉड समाधान के लिए आउटपुट 0 होगा)।

नमक के साथ ले:

#include <stdio.h>
#include <sys/time.h>
#include <stdlib.h>

extern doNothing(int,int); // Empty function in another compilation unit

int main() {
    int i;
    struct timeval timeval;
    struct timeval timeval2;
    div_t result;
    gettimeofday(&timeval,NULL);
    for (i = 0; i < 1000; ++i) {
        result = div(i,3);
        doNothing(result.quot,result.rem);
    }
    gettimeofday(&timeval2,NULL);
    printf("%d",timeval2.tv_usec - timeval.tv_usec);
}

आउटपुट: १५०

#include <stdio.h>
#include <sys/time.h>
#include <stdlib.h>

extern doNothing(int,int); // Empty function in another compilation unit

int main() {
    int i;
    struct timeval timeval;
    struct timeval timeval2;
    int dividend;
    int rem;
    gettimeofday(&timeval,NULL);
    for (i = 0; i < 1000; ++i) {
        dividend = i / 3;
        rem = i % 3;
        doNothing(dividend,rem);
    }
    gettimeofday(&timeval2,NULL);
    printf("%d",timeval2.tv_usec - timeval.tv_usec);
}

आउटपुट: 25


5

ऊपर उल्लिखित के अलावा std :: div कार्यों का परिवार, वहाँ भी है std :: remquo कार्यों का परिवार, लौट रेम -ainder और हो रही यथास्थिति -tient के माध्यम से एक पारित कर दिया-इन सूचक।

[संपादित करें] यह std की तरह दिखता है :: remquo वास्तव में सब के बाद भागफल वापस नहीं करता है


3

बाकी सभी समान हैं, सबसे अच्छा समाधान वह है जो स्पष्ट रूप से आपके इरादे को व्यक्त करता है। इसलिए:

int totalSeconds = 453;
int minutes = totalSeconds / 60;
int remainingSeconds = totalSeconds % 60;

संभवतः आपके द्वारा प्रस्तुत तीन विकल्पों में से सर्वश्रेष्ठ है। हालाँकि, अन्य उत्तरों में बताया गया है कि यह divविधि आपके लिए एक ही बार में दोनों मानों की गणना करेगी।


3

आप 32 बिट इंटेल प्लेटफॉर्म पर 64 बिट पूर्णांक के साथ g ++ 4.6.3 पर भरोसा नहीं कर सकते। a / b को divdi3 के लिए एक कॉल द्वारा गणना की जाती है और एक% b को moddi3 के लिए एक कॉल द्वारा गणना की जाती है। मैं एक उदाहरण के साथ भी आ सकता हूं जो इन कॉल के साथ / b और ab * (a / b) की गणना करता है। इसलिए मैं c = a / b और ab * c का उपयोग करता हूं।

Div विधि एक फ़ंक्शन को कॉल देती है जो div संरचना की गणना करती है, लेकिन एक फ़ंक्शन कॉल उन प्लेटफार्मों पर अक्षम लगता है जिनके पास अभिन्न प्रकार (यानी 64 बिट पूर्णांक / 64 बिट इंटेल / एएमडी प्लेटफार्मों पर हार्डवेयर समर्थन) है।


-4

शेष पाने के लिए आप एक मापांक का उपयोग कर सकते हैं। हालांकि @ cnicutar का जवाब साफ / अधिक प्रत्यक्ष लगता है।


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