সি ++ পূর্ণসংখ্যা বিভাগ এবং বাকী অংশ পাওয়ার সেরা উপায়


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
তৃতীয়টি বিএডি বিকল্প: টিএমপি = 54.999999999999943157 হলে কী হবে? এটি বলেছে, পুরানো স্টাইলের কাস্টিং কখনই করা উচিত নয়।
জিমফিকি

উত্তর:


98

X86-এ বাকীটি স্বয়ং বিভাগের একটি উপ-পণ্য, সুতরাং কোনও অর্ধ-শালীন সংকলক কেবল এটি ব্যবহার করতে সক্ষম হবে (এবং divআবার সঞ্চালন করবে না )। এটি সম্ভবত অন্যান্য আর্কিটেকচারেও করা হয়ে থাকে।

নির্দেশনা: DIVএসসিআর

দ্রষ্টব্য: স্বাক্ষরবিহীন বিভাগ "এসসিআর" দ্বারা সঞ্চয়কারী (এএক্স) ভাগ করে। বিভাজক যদি বাইট মান হয় তবে ফলাফলটি AL এ দেওয়া হয় এবং বাকী এএইচ তে থাকে । যদি বিভাজক একটি শব্দের মান হয় তবে DX: AX কে "src" দ্বারা বিভক্ত করা হয় এবং ফলাফলটি AX এ সংরক্ষণ করা হয় এবং বাকী অংশটি DX এ সংরক্ষণ করা হয়

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

9
আমি মনে করি অনেক পোপল প্রাথমিক বিদ্যালয় থেকে জানেন যে একটি বিভাগ করার সময় আপনি বাকীটি বিনামুল্যে পান। আসল প্রশ্নটি হ'ল: আমাদের সংকলকরা কি এটার সুবিধা নিতে যথেষ্ট স্মার্ট?

1
@ জেডিভি: আমি অবাক হব না। এটি একটি খুব সাধারণ অপ্টিমাইজেশন।
জন পুরী

68
আমি দ্রুত পরীক্ষা করার চেষ্টা করেছি। জি ++ ৪.৩.২ -ও -২ ব্যবহার করে, এসেম্বলারের আউটপুটটি এটিকে একটি idivlনির্দেশিকা ব্যবহার করে এবং ফলগুলি ইক্স এবং এডএক্স ব্যবহার করে স্পষ্টভাবে দেখায় । না পারলে আমি হতবাক হয়ে যেতাম।
ফ্রেড লারসন

2
@ ইউরিপিনহলো সম্মত হন এটি x86 সম্পর্কে কোনও প্রশ্ন নয়। আমি কেবল এটি একটি উদাহরণ হিসাবে দিয়েছিলাম, অত্যন্ত সন্দেহজনক ধারণা নিয়ে অন্যান্য আর্কিটেকচার সম্ভবত কিছু একই কাজ করে।
cnicutar

3
আপনাকে কমপ্লেক্সটি অপ্টিমাইজ করতে বলা দরকার, যদিও কমপক্ষে জি ++ এর জন্য। X86_64- তে জি ++ 6.3.0 নিয়ে একটি সাধারণ পরীক্ষা থেকে জানা গেছে যে কোনও অপ্টিমাইজেশন না করেই আপনি দুটি idivlনির্দেশনা পেয়ে থাকেন তবে এর -O1চেয়ে বেশি বা এর চেয়ে বেশি আপনি একটি পান। ম্যানুয়াল, বলছেন হিসাবে "কোনো অপ্টিমাইজেশান বিকল্প ছাড়া ... বিবৃতি স্বাধীন"
টম জিচ

80

std::div ফলাফল এবং বাকী উভয়ই একটি কাঠামো প্রদান করে।


5
আমি জানতে আগ্রহী যে এটি একটি আধুনিক সংকলকটির বিকল্প 1 এর চেয়ে আরও বেশি দক্ষ কিনা।
গ্রেগ হাওয়েল

2
ভাল লাগল, আমি জানতাম না। এটা কি দ্রুত?

খুশী হলাম। কোনওটি দীর্ঘস্থায়ীভাবে কোথাও প্রয়োগ করা হয় কিনা তা আপনি জানতে পারবেন?
কুকি

@ কুকি: সি ++ 03 এর কোনও ধারণা নেই long longতবে এটি সম্ভবত আপনার সংকলকটির এক্সটেনশন হিসাবে long longঅতিরিক্ত ওভারলোড রয়েছে std::div
iljarn

@ গ্রেগ: আমি মনে করি না যে এটি সম্ভবত, মেমরির কোনও কাঠামোর কাছে ফল লিখতে হবে এবং এটি ফিরিয়ে দিতে হবে, যা (এটি যদি ইনলাইন হিসাবে সংকলন না করে এবং কাঠামো অ্যাক্সেস অপ্টিমাইজড না করা হয়) করাকে চেয়ে বড় শাস্তি হয় একটি অতিরিক্ত বিভাগ নির্দেশ।
15:41

28

কমপক্ষে x86 এ, g ++ 4.6.1 কেবল আইডিআইভিএল ব্যবহার করে এবং সেই একক নির্দেশনা থেকে উভয়ই পায়।

সি ++ কোড:

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

নমুনা কোড টেস্টিং ডিভ () এবং সংযুক্ত বিভাগ ও মোড। আমি এটিগুলিকে জিসিসি -৩৩ দিয়ে সংকলন করেছি, কম্পাইলারটিকে সবকিছু অপ্টিমাইজ করা থেকে বিরত রাখতে আমাকে ডোনিংয়ে কিছু করতে হবে না (বিভাজন + মোড সমাধানের জন্য আউটপুট 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);
}

আউটপুট: 150

#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

উপরোক্ত ছাড়াও এসটিডি :: DIV আছে ফাংশন পরিবার, রয়েছে এসটিডি :: remquo ফাংশন পরিবার, আসতে REM -ainder এবং পেয়ে স্থিতাবস্থা -tient এর মাধ্যমে একটি পাস-ইন পয়েন্টার।

[সম্পাদনা:] দেখে মনে হচ্ছে std :: রিমোকো ঠিক পরে ভাগফলটি ফেরায় না


3

সমস্ত কিছুই সমান, সর্বোত্তম সমাধান হ'ল এটি আপনার উদ্দেশ্যকে স্পষ্টভাবে প্রকাশ করে। তাই:

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

আপনার উপস্থাপিত তিনটি বিকল্পের মধ্যে এটি সম্ভবত সেরা। অন্যান্য উত্তরে যেমন উল্লেখ করা হয়েছে, divপদ্ধতিটি আপনার জন্য একই সাথে উভয় মান গণনা করবে।


3

আপনি 32+ বিট ইন্টেল প্ল্যাটফর্মে 64 বিট পূর্ণসংখ্যার সাথে জি ++ 4.6.3 এ বিশ্বাস করতে পারবেন না। a / b কে divdi3 এ কল করে গণনা করা হয় এবং% b কে moddi3 এ কল করে গণনা করা হয়। এমনকি আমি এমন একটি উদাহরণ হাজির করতে পারি যা এই কলগুলির সাথে একটি / বি এবং আব * (a / b) গণনা করে। সুতরাং আমি সি = এ / বি এবং আব * সি ব্যবহার করি।

ডিভ পদ্ধতিটি একটি ফাংশনে কল দেয় যা ডিভ কাঠামোটি গণনা করে তবে একটি ফাংশন কলটি প্ল্যাটফর্মগুলিতে অকার্যকর বলে মনে হয় যা ইন্টিগ্রাল টাইপের (যেমন have৪ বিট ইন্টেল / এমডি প্ল্যাটফর্মে bit৪ বিট ইন্টিজার) হার্ডওয়্যার সমর্থন করে plat


-4

বাকিটি পেতে আপনি একটি মডুলাস ব্যবহার করতে পারেন। যদিও @ সিনিকুটারের উত্তর পরিষ্কার / আরও সরাসরি বলে মনে হচ্ছে।


2
হ্যাঁ, আসল পোস্টারটি মডুলাস অপারেটর ব্যবহার করেছে, প্রশ্ন কীভাবে এটি দক্ষ করবেন।
লাকাটা
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.