2011-08-15 5 views
72

私はaをbで除算したいと思っていますが、結果cと剰余の両方に興味があります(例えば秒数があり、数分と数秒で)、それについての最良の方法は何ですか?C++整数の除算と剰余を得る最良の方法

それは多分一度に1の両方を与える魔法の機能がある

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); 

または

だろうか?

+4

以下のすべての回答は妥当と思われますが、私はちょうど 'ダブル '(あなたの最後のアイテム)のマックは私には悪いアイデアのように思えます、あなたは整列していない数字に終わるでしょうパフォーマンスと実行可能なサイズであなたを犠牲にすることができます(特定の組み込みシステムではいつも問題でした)。 – nhed

+2

3つ目はBADオプションです:tmp = 54.999999999999943157の場合はどうなりますか? これは古いスタイルのキャスティングは決して賢明なことではないと言いました。 – jimifiki

答えて

71

x86では残りの部分は除算自体の副産物なので、半分のコンパイラであればそれをそのまま使用できます(divを再度実行しないでください)。これはおそらく他のアーキテクチャでも行われます。

命令:DIV SRC

注:符号なし除算。アキュムレータ(AX)を "src"で除算します。 がバイト値の場合、結果はAL になり、余りはAHになります。除算値 がワード値の場合、DX:AXは「src」で除算され、結果は でAX に格納され、残りはDXに格納されます。

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

私は、小学校から分科会をするときに余分なものを無料で得ることを多くの人が知っていると思います。本当の疑問は、私たちのコンパイラはこれを利用するのに十分なスマートなのでしょうか? –

+0

同意 - しかし、bが2の累乗であれば、ビットシフトを使うことができます。 –

+1

@jdv:私は驚かないでしょう。それは非常に単純な最適化です。 –

57

std::div結果、残りの両方で構造体を返します。

+4

現代のコンパイラで、これが実際にはオプション1よりも効率的かどうかを知りたいのです。 –

+2

ニース、私は知らなかった。それは速いですか? –

+0

ニース。どこか長い間長い間実装されているかどうか知りたいですか? – Cookie

-3

モジュラスを使用して余りを得ることができます。 @ cnicutarの答えはより洗練された/より直接的だと思われるが。

+1

はい、オリジナルのポスターはモジュラス演算子を使用しました。問題はそれを効率的にする方法です。 –

3

他のすべてが等しい場合、最良の解決策は、あなたの意図をはっきりと表現することです。だから、:

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

は、おそらくあなたが提示の3つのオプションのが最善です。しかし、他の回答に記載されているように、divメソッドは、両方の値を同時に計算します。

+3

明らかに質問はスピードについて質問しています... – Pacerier

21

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 
+0

注文は問題ですか?たとえば、 '/ ='を反復している場合、まず分割を維持するために一時変数を使用する必要があります。 – Annan

6

サンプルコード試験DIV()と組み合わせて分割& MOD。私はgcc -O3でこれらをコンパイルしました。私はdoNothingの呼び出しを追加してコンパイラがすべてを最適化するのを止めなければなりませんでした(出力はdivision + modソリューションのために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

3

をあなたは上の64ビットの整数で、ここでG ++ 4.6.3を信頼することはできません32ビットインテルプラットフォーム。 a/bはdivdi3の呼び出しによって計算され、%bはmoddi3の呼び出しによって計算されます。私はこれらの呼び出しでa/bとa-b *(a/b)を計算する例を考え出すこともできます。ですから私はc = a/bとa-b * cを使います。

divメソッドはdiv構造体を計算する関数を呼び出しますが、整数型(つまり、64ビットintel/amdプラットフォームの64ビット整数)のハードウェアをサポートしているプラ​​ットフォームでは、関数呼び出しは非効率的です。

5

は、機能の前述のstd::div家族に加えて、機能のstd::remquo家族があり、渡されたポインタを経由してレム -ainderと現状 -tientを得ることを返します。

[編集:]結局、std :: remquo doesn't really return the quotientのように見えます。

関連する問題