高速に加算の繰り上がり部分を計算する方法

このQ&Aのポイント
  • int型の変数a,bの加算を高速に行う方法を紹介します。繰り上がり部分の処理を最適化するため、ビット演算を使用します。
  • int型の変数a,bの加算における繰り上がり部分の処理を高速化する方法を解説します。ビット演算を活用することで、効率的な計算が可能です。
  • int型の変数a,bの加算における繰り上がり部分を効率的に処理する方法を紹介します。コード例を交えながら、高速な計算方法をご説明します。
回答を見る
  • ベストアンサー

加算の繰り上がり部分を高速に計算

int型の変数a,bの加算を行う場合、 繰り上がり部分の処理が面倒ですが、 以下のようなコードを書きました。 cが繰り上がり部分となります。 #include <stdio.h> int main() { int a=1111; int b=458778; int N=31; int c=0; int flg=0; int bit=1; for(int i=0;i<N;i++){ if(flg)c^=bit; int ai=a & bit; int bi=b & bit; if(!flg && ai && bi)flg=1; else if(flg && !ai && !bi){ flg=0; } bit<<=1; } printf("%d\n",a+b); printf("%d\n",a^b^c); } この処理を可能な限り早く行いたいのですが、 どのような手法があるでしょうか?

質問者が選んだベストアンサー

  • ベストアンサー
  • ki073
  • ベストアンサー率77% (491/634)
回答No.6

ちょっとおもしろそうなので、やってみました。 四則演算を使わないというふうに勝手に判断して書いてみました。 #define N 31 inline int fn1(int a, int b) { int c=0; int flg=0; int bit=1; for(int i=0;i<N;i++){ int ai=a & bit; int bi=b & bit; flg = ((ai & bi) | (ai & flg) | (bi & flg)); flg<<=1; c|=flg; bit<<=1; } return c; } ついでに計算時間も計りました。(10000000回ループを回したときの時間です) 上のプログラム 0m0.653s No.4のプログラム 0m0.798s 質問欄のプログラム 0m2.327s 一般的な高速化の方法ですが、 1) if文などの条件判断をLoopの中から極力排除する。(パイプラインの関係) 2) テーブル引きを、可能なら関数などレジスタで計算できるようにする。 3) ここでは使っていませんが、ループのデータ依存関係を排除する (SSEなどベクトル演算ができる) などです。測定プログラムを書いておきます。 乱数で数値を発生させています。またsumをちょっと余分につけています。結果をその都度出力していたら、出力の時間を計っているようになるので、それとコンパイラによっては最適化で計算を省略することを防ぐためです。 ちなみに、randやsumの関数の計算と関係ない以部分は0m0.182sです。 #include <stdio.h> #include <stdlib.h> int main() { int a, b, c; int sum=0; for(int j=0; j<10000000; j++){ a=rand()/4; b=rand()/4; c=fn2(a, b); sum=sum+c; } printf("%d\n",sum); }

ibm_111
質問者

お礼

ありがとうございます。 確認いたしました。速いですね。

その他の回答 (5)

  • nag0720
  • ベストアンサー率58% (1093/1860)
回答No.5

1ビット単位で繰上げの判定をしたいということでしょうか? 1ビット単位が原則なら、質問文のプログラムのようにif文で判定するか、No.4さんのように配列を使うか、もしくは、ビット論理式で計算するしかないでしょう。 なぜa ^ bを計算してはいけないのか分かりませんが、2ビット単位とか、4ビット、8ビット単位で計算することもだめなのでしょうか。

  • wormhole
  • ベストアンサー率28% (1620/5655)
回答No.4

早いかどうかわかりませんけど。 int carray_tbl[][][] = { { { 0, 0 }, { 0, 1 } }, { { 0, 1 }, { 1, 1 } }, }; int main() { int a = 1111; int b = 458778; int c = 0; int N = 31; int ta = a; int tb = b; int cf = 0; for (int i = 0; i < N; i++) { cf = carray_tbl[ta & 1][tb & 1][cf]; ta >>= 1; tb >>= 1; c |= cf << (i + 1); } printf("%d\n", c); return 0; }

回答No.3

早いかどうかわからないけど、 #include <stdio.h> int main(void) { int a = 1, b = 2, c, f; c = a ^ b; f = (a & b) << 1; while(f){ int d = (c ^ f); f = (c & f) << 1; c = d; } printf("%d + %d = %d\n", a, b, c); return 0; }

ibm_111
質問者

お礼

重要なことをお伝えするのを忘れてました。 a ^ bは計算しないようにしてください。 ここで苦労してます。

  • honor
  • ベストアンサー率35% (25/71)
回答No.2

比較はしてないのでどちらが早いかは分かりませんが、 奇数ビットと偶数ビットの繰り上がりを分けて出すのは如何ですか。

ibm_111
質問者

お礼

なるほど。考えてみます。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.1

「int型の変数a,bの加算を行う」なら素直に a+b と書けばいい. なぜこんな面倒くさいことを考える?

ibm_111
質問者

お礼

詳細は申し上げられませんが、仕事上の理由です。

関連するQ&A

  • 2進数の加算の繰り上がり

    2進数の四則演算のプログラムを作りたいと思い、2進数を表示するところまではできたのですが、加算になると繰り上がりという壁にぶつかってしまいました。繰り上がりや桁上げなどがよく分からないので、お教えください。(下のソースコードが繰り上がりのない加算をするまでのものです) #include <stdio.h> int main(void) { int a,b,i,j,x[8],y[8],z[8]; do{ puts("二つの符号なし整数を入力してください。(ただしa>bとし、bはのべき乗の値とする)"); printf("a="); scanf("%d",&a); printf("b="); scanf("%d",&b); if(a < = b) puts("入力した値がa>bになっていません。\a"); }while(a < = b); for( i = 0; i < = 7; i + +){ x[i] = a % 2; a = a / 2; y[i] = b % 2; b = b / 2; } puts("aとbをそれぞれ二進数で表すと"); printf("a="); for( i = 7; i > = 0; i - -){ printf("%d",x[i]); } puts(""); printf("b="); for( i = 7; i > = 0; i - -){ printf("%d",y[i]); } printf("となります。\n\n"); printf("<加算>\n"); printf("c=a+b="); for( j = 7; j > = 0; j - -){ z[j]=x[j]^y[j]; printf("%d",z[j]); } return(0); }

  • 外積のプログラムについて質問があります

    ベクトルの外積のプログラムについて質問があります 環境はリナックスです 問題は2つの実ベクトルa,bをキーボードから入力しその外積を求めるプログラムです i<jである組み合わせに対してai*bj-aj*biを並べたものです 次元nについてはキーボードから入力します wedge内で外積を求める計算をします #include <stdio.h> int *wedge(int *a, int *b, int *c); int main() { int n; int a[100]; int b[100]; int i; int j; printf(" nの値を入力" ); scanf("%d", &n); for(i = 0; i < n; i++){ scanf("%d",&a[i]); } for(i = 0; i < n; i++){ scanf("%d",&b[i]); } for(i = 0; i < n; i++){ printf("a[%d]=%d\n",i, a[i]); } for(i = 0; i < n; i++){ printf("b[%d]=%d\n",i, b[i]); } } int *wedge(int *a, int *b, int *c) { int i; int j; *c = a[i] * b[j] - a[j] * b[i]; if ( i < j ){ *c = a[i] * b[j] - a[j] * b[i]; } else { *c = 0 ; } printf("*c = %d",a[i] * b[j] - a[j] * b[i]); } このようなプログラムを作ったのですが外積を表示させることができません。 修正したプログラムをおしえていただけないでしょうか

  • C言語における複素数の四則演算について

    複素数の四則演算(a+biとc+diの四則演算)について、for文を用いて表示するプログラムについて、???の部分に何を入れたらよいかわからず、うまく実行することができません。和・差・積・商の計算種別を入れるみたいなのですが、何を入れたらいいのかわかりません。 #include <stdio.h> void fukuso(double a,double b,double c,double d,double *e,double *f,int keisan); int main(void) { double a=4, b=8, c=4, d=3, e, f; int i; for(i=1;i<5;i++){ fukuso(a,b,c,d,&e,&f,???); if(i==1) printf("和演算\n"); else if(i==2) printf("差演算\n"); else if(i==3) printf("積演算\n"); else printf("商演算\n"); printf("e=%f f=%f i\n",e,f); } return (0); } void fukuso(double a1,double b1,double a2,double b2,double *a3,double *b3,int keisan) { if(keisan==1){ *e=a+c; *f=a+c; } else if(keisan==2){ *e=a-c; *f=b-d; } else if(keisan==3){ *e=a*c-b*d; *f=a*d+c*b; } else{ *e=(a*c+b*d)/(c*c+d*d); *f=(-a*d+c*b)/(c*c+d*d); } }

  • AIZU ONLINE JUDGEについて

    明らかに正常なコードなのに答えが間違っているとされます。 #include<stdio.h> int main(void) { int a, b, c, N, i; scanf("%d",&N); for (i = 0; i < N; i++) { scanf("%d %d %d", &a, &b, &c); int A = a*a; int B = b*b; int C = c*c; if ((A + B == C) || (B + A == C )|| (C + A == B)) { printf("YES\n"); } else { printf("NO\n"); } } return 0; } これはvisual studio では通りました。 ちなみにこのコードは自分のものと酷似していますが、これはAIZU的にはOKだそうです。 #include <stdio.h> int main(void) { int a, b, c, n, i; scanf("%d",&n); for (i = 0; i < n; ++i) { scanf("%d %d %d", &a, &b, &c); if ((a*a + b*b == c*c) || (b*b + a*a == c*c) ||( c*c + a*a == b*b)) printf("YES\n"); else printf("NO\n"); } return 0; } この違いはなんでしょうか?

  • 長方形、円、三角形の計算するプログラムでエラーがでます

    タイトルの通りなんですがエラーがでます>< コンパイラはできたのですが、実行して二つ目の入力するとこで、入力したあと止まります。 どこがおかしいのでしょうか? #include <stdio.h> int sikaku(void); int en(void); int main(void) { char ch; int a,b; printf("円(A) 長方形(B) 三角形(C)\n"); printf("入力してください:"); ch = getche(); if(ch == 'C'){ printf("\n底辺を入力してください:"); scanf("%d ",a); printf("高さを入力してください:\n"); scanf("%d",b); printf("%dです",a * b); } else if(ch == 'B') sikaku(); else if(ch == 'A') en(); return 0; } int en(void) { int a; float f; printf("\n半径を入力してください:"); scanf("%d",a); printf("円周率を入力してください:"); scanf("%f",f); printf("%fです",a * a * f); return 0; } int sikaku(void) { int a,b; printf("\n縦を入力してください:"); scanf("%d",a); printf("横を入力してくさい:\n"); scanf("%d",b); printf("dです",a * b); return 0; }

  • 3つの入力した数値の大小比較ができません。

    #include<stdio.h> int main() { int a,b,c; scanf("%d",&a); scanf("%d",&b); scanf("%d",&c); if(a<b) { if(b<c) { if(a<c) { printf("%d<%d<%d\n",a,b,c); } else { printf("%d%d%d",a,b,c); } } if(b>c) { if(a>c) { printf("%d<%d<%d\n",c,b,a); } else { printf("%d<%d<%d\n",a,c,b); } } } else if(a>b) { if(b>c) { if(a>c) { printf("%d>%d>%d\n",a,b,c); } else { printf("%d>%d>%d\n",a,c,b); } } else if(b>c) { if(a>b) { printf("%d>%d>%d\n",a,b,c); } else { printf("%d>%d>%d\n",b,a,c); } } else if(c>b) { if(c>a) { printf("%d<%d<%d\n",b,a,c); } else { printf("%d>%d>%d\n",a,c,b); } } else if(a<c) { if(a<b) { printf("%d<%d<%d\n",a,b,c); } else { printf("%d<%d<%d\n",b,a,c); } } else if(a>c) { if(a<b) { printf("%d>%d>%d\n",b,a,c); } else { printf("%d>%d>%d\n",a,b,c); } } else { printf("%d=%d=%d\n",a,b,c); } } 間違っている部分を教えてください。

  • forkとグローバル変数について

    上記タイトルについて質問です。 グローバル変数で定義した変数(int型) をforkで作成した子プロセス間で使用したいのですがうまくいきません。実際には以下のように定義しています。 int flg=0; main() {  if(( i=fork() )==0){  flg = 1; /* こっちをA */  } else {  sleep(3);  printf(" flg=%d\n", flg ); /* こっちをB */  } } こういった使い方は間違いなのでしょうか? また、上記にてA側で変更したグローバル変数の値をB側でも使用することが出来る方法を教えて下さい。(グローバル変数以外でも同様の処理が行えればそれでもいいので教えて下さい。)

  • 高速フーリエ変換に関すること

    皆様、こんばんわ。 今日は、お聞きしたいことが会ってここに質問しにきました。 まず、こちらを見てください。 これは、「毎回異なる計算結果を、順次足していく」、 そのための練習用プログラムです。 #include<stdio.h> int main(void){ int i,j; int z[3]={0}; int a[5]={1,2,3,4,5}; int b[5]={5,4,3,2,1}; for(i=0;i<3;i++){ for(j=0;j<5;j++) Z[i] += a[j]*b[j]; if (i==1) z[i]=z[1] else (i>1) z[i]+z[i-1] } printf("a = {%d,%d,%d,%d,%d}\n",a[0],a[1],a[2],a[3],a[4]); printf("b = {%d,%d,%d,%d,%d}\n",b[0],b[1],b[2],b[3],b[4]); for(i=0;i<3;i++) printf("z[%d] = %d\n",i,z[i]); return(0); } 流れとしては、 (1)2つの配列の各要素の積の計算をする。 (2)そして、計算して出た積(全部で5つ)を足す。 (3) (1)~(2)の計算を繰り替えす。 (但し、1回目以降は前回の計算結果を足す) そして最終的に、 a[5] = {1,2,3,4,5} b[5] = {5,4,3,2,1} Z1 = 35 Z2 = 70 Z3 = 105 という結果を出力したいんです。 ですが、どうしてもエラーが起きて実行できません。 たぶんですが、if-else文の辺りが違うと思うのですが・・・。 どういう風に変更したらいいのでしょうか? ちなみに使っているコンパイラVidualC++2008です。 OSはVistaです。

  • c言語で分からないところがあるので教えてください。

    http://www9.plala.or.jp/sgwr-t/c/Q/ens06-61.html の問題がわかりません。 回答の #include <stdio.h> int main( void ) { int kekka[51]; int a, b, i; int amari; printf( "整数値を2つ入力してください " ); scanf( "%d%d", &a, &b ); if( b == 0 ){ printf( "処理終了\n" ); return 0; } printf( "%d / %d = ", a, b ); kekka[0] = a/b; for ( i = 1; i < 51;i++ ) { amari = a%b; if ( amari == 0 ) break; a = amari * 10; kekka[i] = a/b; } printf( "%d.", kekka[0] ); ここまでの部分はわかったのですが、 下の for ( a = 1; a < i; a++ ) { printf( "%d", kekka[a] ); } の部分がわかりません。 この部分は何を表わしているのか 教えてください。

  • 整数を3つ読み込み、一番大きいものを表示するプログラム

    3つが違う数であるとしてこうしたんですが、 #include<stdio.h> int main() {int a,b,c; scanf("%d",&a); scanf("%d",&b); scanf("%d",&c); if(a>b && a>c){ printf("%d\n",a);} if(b>a && b>c){ printf("%d\n",b); if(c>a && c>b){ printf("%d\n",c); }}return 0;} で、コンパイルはできたんですが、実行できません。3つの数値を入力してもその一番大きい数が出てきません。ifの条件は間違ってはいないと思うんですがやはり、最大が2つあるときのことを考えないとできませんか?

専門家に質問してみよう