実行時間の計測(C言語)における不可思議な現象とその理由

このQ&Aのポイント
  • C言語においてfor文の2億回ループする場合の実行時間を計測した結果、加算する回数(a++)が増えているにも関わらず、実行時間が変わらない場合や短くなる場合がある。
  • (1)~(2)の場合、加算する回数(a++)が増えているのに実行時間が変わらない理由はアセンブラに直すと確かに加算回数は増えているが、レジスタの使用方法が最適化されているために実行時間が変わらないと推測される。
  • (6)~(7)の場合、加算される回数が一定数である場合と比べて、加算する変数の数が増えることでメモリのアクセスパターンが最適化され、キャッシュミスが減るため実行時間が短くなると推測される。
回答を見る
  • ベストアンサー

実行時間の計測(C言語)

実行時間について教えてください。 実行時間について不可思議な現象が起きたので疑問に思いました。 C言語においてfor文の2億回ループする場合の実行時間を計測し、計測する内容を変えます。 以下のプログラムのように、時間を計測します。 --------------------        ・        ・ gettimeofday(&t0, NULL);  (計測したい処理) gettimeofday(&t1, NULL);        ・        ・ --------------------- (計測したい処理)に以下のようなプログラムを入れ時間を計測しました。 以下、(計測したい処理)  → それにかかった実行時間 <実行結果 書式(計測したい処理) → 計測された時間 > (1)for ( i = 0; i < 2000000000; i++);         →  5.412432 sec (2)for ( i = 0; i < 2000000000; i++, a++);      →  5.401164 sec (3)for ( i = 0; i < 2000000000; i++, a++,a++);   →  9.340447 sec (4)for ( i = 0; i < 2000000000; i++, a++,a++,a++);   →  13.985456 sec この結果を受けての疑問(1) (2)~(4)までは、加算する回数(a++)が2倍、3倍と増えたため、線形的に実行時間が増えるという理屈で納得できるのですが、 (1)~(2)について、加算する回数(a++)が増えているのに、なぜ実行時間が(1)と(2)では変わらないのか。 アセンブラに直すと、確かに加算回数は増えているはずです。 <実行結果 書式(計測したい処理) → 計測された時間 > (5)for ( i = 0; i < 2000000000; i++);           →  5.412432 sec (6)for ( i = 0; i < 2000000000; i++, a++);        →  5.401164 sec (7)for ( i = 0; i < 2000000000; i++, a++,b++);     →  4.019215 sec (8)for ( i = 0; i < 2000000000; i++, a++,b++,c++);   →  4.008310 sec   実行結果を受けての疑問(2) なぜ、(6)~(7)では、加算される回数は増えているにも関わらず、 (5)より実行時間は短くなっているのか。 ((3)と(7)の時間差があることについは、対象となるレジスタが違うため、並行処理をしていると推察できることはわかります。今回は(5)~(8)にかけて、なぜ実行時間が短くなるのかという質問です。) <前提> ・前提として、プログラム内容に間違いはない。 ・バックグラウンドで動いているプログラムの影響は受けていないとします。 (何度も実行して確認しているので常にこのような結果が得られました。) 疑問1、2について、推測できる理由を教えてください。 <環境> ・Windows7 Corei5 上で VMwareによってUbuntuで実行しています。(VMwareのコア数の設定は1) ・メモリはWindowsOS、VMwareによる設定共に2GB <ソース> #include <stdio.h> #include <sys/time.h> // gettimeofday int main() { struct timeval t0, t1; long l; long i; long h; long j; long k; i = 0; h = 0; l = 0; j = 0; k = 0; gettimeofday(&t0, NULL); for ( i = 0; i < 2000000000; i++,l++,h++,j++); /*この部分の加算を変更して計測しています。*/ gettimeofday(&t1, NULL); printf("i = %ld, l = %ld, h=%ld \n",i,l,h); t1.tv_sec -= t0.tv_sec; if (t1.tv_usec < t0.tv_usec) { t1.tv_sec -= 1; t1.tv_usec += 1000000 - t0.tv_usec; } else { t1.tv_usec -= t0.tv_usec; } printf("%d.%06d sec\n", t1.tv_sec, t1.tv_usec); } わかる方、回答を何卒お願いします。 (解答に必要な条件が足りないのでしたら、教えてください。すぐに追記します。)

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

  • ベストアンサー
noname#208507
noname#208507
回答No.7

書き忘れました。私が試したのは 64bit の Ubuntu 12.04 です。 それから前言を撤回します。仮想環境でなくても1,2間で処理時間が増えない場合はありますね。 別のPCも含めて、再度試してみました。 -------------------------- Ubuntu 12.04 (64bit) Core i7-3720QM 2.6 GHz (8 core) (1) 3.431967 sec (2) 3.943790 sec (3) 6.874282 sec (4) 10.425479 sec (5) 3.392887 sec (6) 3.918412 sec (7) 4.458465 sec (8) 3.947680 sec -------------------------- Vine 6.0 (32bit) Core2 Duo T7250 2.0 GHz (2 core) (1) 7.082609 sec (2) 7.086212 sec (3) 12.156981 sec (4) 18.270035 sec (5) 7.082886 sec (6) 7.069174 sec (7) 7.393213 sec (8) 9.099289 sec -------------------------- Vine 3.2 (32bit) Mobile Celeron 1.8 GHz (1 core) (1) 4.712198 sec (2) 6.769757 sec (3) 13.794606 sec (4) 21.499377 sec (5) 4.516656 sec (6) 6.848446 sec (7) 9.207516 sec (8) 11.300254 sec -------------------------- 全て native install です。また最適化はしていないので、加算命令(64bitはaddq, 32bitはaddl)もCのコードと素直に対応しています。やはり古いCeleronは、他よりも処理が時間に反映されている気がしますね。 同じメモリへの加算より、違うメモリへの加算の方が時間の増え方が鈍いです。キャッシュには余裕で入りきるサイズでしょうから、パイプラインが影響している気がしますが。 他の皆さんも言われている通り、要因が多すぎて確かなことは不明です。

nit_dahlia
質問者

お礼

ありがとうございます。 いろいろと実験してくださったんですね。 私も、Corei3にUbunutu12.04をnative installしてみました。 やはり、結果はulist様と同様もののでした。 (私も最適化していません。) >同じメモリへの加算より、違うメモリへの加算の方が時間の増え方が鈍いです 違うメモリへの加算((5)~(8))の実行時間が増えにくいのは、 ほぼパイプラインの影響でしょうね。 (1)(2)間もしkは、(5)(6)間で基本的に、実行時間があまり増えない理由が いろいろ調べているのですが、まだ分からないです。 Celeronの結果を見ると、 (2)~(4)では線形的に時間が増えていっていて、 つじつまが合いますよね。 しかし、(1)~(2)間だけがどうしても説明ができない…。 どこに理由があるのでしょうね。

その他の回答 (8)

  • davidfox
  • ベストアンサー率58% (21/36)
回答No.9

(1)と(2)の違いのみ: Pentium II 256MHz で試しました。 (1)より(2)が若干早くなりました。 (1) 54.862378 sec (2) 53.012287 sec そこで、nop を幾つか挟んでみた処... for ( i = 0; i < 2000000000; i++) { __asm__("nop"); __asm__("nop"); } かなり早くなりました。 (1') 46.948590 sec ... nop x 2 挿入 パイプライン処理は詳しくありませんが、nop の挿入数でかなり変わるので、その構造にマッチしているか、していないかの違いではないかと思います。 for 部のアセンブリコードは以下でした(2つ混在させた為、ラベルが異なる)。 (2)のコード movl $0, -24(%ebp) .p2align 2 .L4: cmpl $1999999999, -24(%ebp) jle .L6 jmp .L8 .p2align 2 .L6: leal -24(%ebp), %eax incl (%eax) leal -20(%ebp), %eax incl (%eax) jmp .L4 .p2align 2 (1')のコード .L21: nop movl $0, -24(%ebp) .p2align 2 .L27: cmpl $1999999999, -24(%ebp) jle .L30 jmp .L8 .p2align 2 .L30: #APP nop nop #NO_APP leal -24(%ebp), %eax incl (%eax) jmp .L27 .p2align 2 .L8:

noname#208507
noname#208507
回答No.8

> しかし、(1)~(2)間だけがどうしても説明ができない…。 おや? Celeronの話ですよね。 読み書きするメモリアドレスの同異が影響していると仮定するなら、(1),(2)間が(2)以降より時間の増え方が鈍いのは筋が通るのではないでしょうか。i++ と a++ ではアドレスが違うので。 他のCPUの(5)(6)などは、これだけでは説明がつかないですが。 i は分岐予測に関わってくるので他の変数と扱いが変わってくるのでは、くらいの想像しか思いつきません。

nit_dahlia
質問者

お礼

申し訳ありません。 少し勘違いをしていました。 おっしゃる通りです(笑) (1)→(2)は説明がつきますね。 ありがとうございます。 Celeronは(1)→(4)(5)→ (8)すべて説明がつきますね。 問題はコアが多い場合ですね。

  • wormhole
  • ベストアンサー率28% (1621/5657)
回答No.6

>今回のプログラムですと、空ループはないと思います。 >なぜなら、後でa++; i++;等、2億回ループしたのですが、 >その変数の中身を表示しているからです。 コンパイラや最適化オプションにもよりますが単純に2億回 a++や i++をやってるだけならループ自体省略して a += 2000000000 などのようにコンパイルされる場合もあります。

nit_dahlia
質問者

お礼

なるほど! 確かにそれでしたら、ループ処理はいらなくなりますね!! (5)(6)の実行時間より、(7)(8)の実行時間が短くなったのは、 そういう理由もあるんでしょうか。 また、gcc -O0 とすれば、これらの最適化も一切行わなくなると思うので、 まだ実行時間が短くなる理由がしっくりきません。。。 とても奥が深いです。

  • tadys
  • ベストアンサー率40% (856/2135)
回答No.5

最近のパソコン用のCPUでは、アセンブラのコードとCPU内の実行が1対1に対応しているわけではないので、コードから実行時間が推測できない場合も有ります。 同時に実行して問題が起きないコードは同時に実行される事が有ります。 例えば、for ( i = 0; i < 2000000000; i++, a++); の場合、 i++と a++が同時に実行されている事は予想の範囲内です。 i++, a++,b++,c++の場合も同様です。 http://d.hatena.ne.jp/hyoshiok/20070916#p1 for ( i = 0; i < 2000000000; i++, a++,a++); の場合、最初のa++と2番目のa++は同時には実行できないんでしょう。 頭の良いコンパイラなら、これを a+=2 に置き換えてしまうかもしれません。 最適化レベルを上げればループそのものを省略してしまうだろうけど。

nit_dahlia
質問者

補足

早速のご回答ありがとうございます。 (2)~(4)については、a++;の個数分、線形的に実行時間が増加しています。 それ以降も、a++;の個数分だけ増えていくんですよね。 i++; a++; だけの場合、同時に実行できるので、なんとなく納得はできる気がしてきました。 ありがとうございます。 しかし、 (5)と(7)を比較すると理解が困難です。 (5)より(7)のほうが実行時間が短いのはなぜなんでしょうか。 並列実行されているとしたら、(5)と(7)が同程度の実行時間になる気がするのですが…。 何か追加でアドバイスがありましたら ご教授お願いします。

noname#215107
noname#215107
回答No.4

初めに言っておきますが、私はその環境についての知識はゼロです。 コンパイラの最適化で、空ループが無視されていませんか? 対策としては下記のように、アセンブラでNOP命令を入れるとどうでしょうか? for ( i = 0; i < 2000000000; i++) {    __asm__("nop");   //←すみません、この書き方が正しいかどうかも知りません(笑) }    

nit_dahlia
質問者

お礼

回答ありがとうございます。 今回のプログラムですと、空ループはないと思います。 なぜなら、後でa++; i++;等、2億回ループしたのですが、 その変数の中身を表示しているからです。 NOP命令についは、初めて知りました。 あまり、アセンブラについはあまり詳しくないので、 アドバイスを元に、アセンブラを勉強してNOP命令など 試してみたいと思います。 また、報告します。

noname#208507
noname#208507
回答No.3

同じプログラムを、Ubuntu 12.04 を native install した環境(Core i7-3720QM)で実行してみました。 (1) 3.393335 sec (2) 4.110268 sec (3) 6.875924 sec (4) 10.391332 sec 一応、1と2の間で増加傾向が見られます。 やはり仮想環境での評価は少し問題があるのでは?

nit_dahlia
質問者

お礼

追加です。 ulist様の(1)~(4)の実行結果なのですが、 処理時間が線形的に増えない理由として、 どのようなことが考えられると思いますか? あらためて、結果を見ていて、疑問に思ったので、 ulist様のご意見も聞いてみたいです!

nit_dahlia
質問者

補足

回答ありがとうございます。 VM上だからってことですか・・・。 一度、native installで実行してみます。 また、実行結果を踏まえて、ご報告させていただきたいと思います。 ちなみに、(5)~(8)の結果についてはいかがでしょうか。

  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.2

> アセンブラに直すと、確かに加算回数は増えているはずです。 実際に、アセンブリにコンパイルして確認したらどうです? gccなら-Sでできます。 あと、コンパイル時のオプション、特に最適化関係はどうなってますか? さすがに、ループを省略する様なのは、設定してない様には見えますが 最近のPCでは、一つのプログラムを全力で実行するようなことはほとんどありません。 キャッシュだの並列化だの、不確定な要素もおおいです。

nit_dahlia
質問者

補足

アセンブラコードも確認しまして、 gcc -S で内容を見てみました。 すると、やはり加算命令がふえているだけの単純なものでした。 a++; → addl $1 16($ep) a++; b++; → addl $1 16($ep)   addl $1 24($ep)  /*アドレス番号は適当です*/ なので、アセンブラを見る限りだけだと、 加算命令回数が増える(当初の予想通り)んですよね。 やはり不可思議です・・・。 また、コンパイルオプションについてですが、 gcc -O0 とし、最適化をせずに実行をしても結果は変わりませんでした。 不確定要素は確かにそうですね。 ・OSのジョブ処理優先順位 ・キャッシュ ・最適化 人の手で制御できないものも考えられますね。 (5)→(7)となる理由はこれらの内容でどう説明したらよろしいでしょうか。

  • yama1718
  • ベストアンサー率41% (670/1618)
回答No.1

VMwareのエミュレータの仮想CPUはプログラムコードが実行できれは良いのであって、動作速度やクロック数まで忠実に再現しているとは思えません。 できるだけ効率が良くなるように最適化されているでしょうね。 それにエミュレータはホストのCPUの処理能力によって仮想環境内の時間進行と現実世界の時間進行に差が出ないように足かせを入れて調整しています。 更にホストはCore i5で4コア(種類によっては2コア)となるともっとややこしくなりますね。 そもそもプログラムコードから各命令のクロック数とCPUの動作周波数から実行速度を正確に計算できるのは旧世代の8ビットCPUぐらいまでか、組み込み系などで特別に設計されたマイコンだけだと思います。

nit_dahlia
質問者

お礼

回答ありがとうございます。 仮想環境が問題なのかもしれませんね。 native installして試してみます。 また、コアが多いとそれはそれで面倒なのかもしれません。 また、実験して報告させていただきます。

関連するQ&A

  • UNIX times関数を用いた時間計測

    以下のようなforkを使用したプログラムの実行時間を計測したいのですが、times関数の使用方法がわかりません。 gettimeofdayを用いて物理的な実行時間を計測することは出来たのですが、 それでは不充分なので、もっと詳細に計測したいのです。 times関数を用いると ・実行中のプロセスが消費したユーザCPU時間 ・実行中のプロセスが消費したシステムCPU時間 ・子プロセスが消費したユーザCPU時間 ・子プロセスが消費したシステムCPU時間 がわかりますよね?sysconf()でクロック時間を得るところまでは出来たのですが、アドバイスお願いします。 #include <stdio.h> #include <sys/time.h> #include <sys/times.h> #include <unistd.h> int main(int argc, char *argv[]) { int val ; struct timeval tv,tw; gettimeofday(&tv,NULL); time = times(&t); switch(fork()) { case 0: exit(0) ; case -1: perror("child process") ; break; default: wait(&val) ; } gettimeofday(&tw,NULL); time = tw.tv_usec - tv.tv_usec; printf("child PID = %d\n",cpid); printf("val = %d\n"); printf("%ldus\n",time); }

  • 処理時間計測

    処理時間計測用関数を #include <sys/timeb.h> struct _timeb tb; double gettimeofday_msec() { _ftime( &tb ); return ((double)tb.time * 1000.0) + ((double)tb.millitm); } と定義したのですが、これをどのように使えばいいのでしょうか? 教えてください。

  • 並列プログラミングのエラー

    6400×6400の行列のベクトル積を並列計算によって求め、その時間を計るプログラムです。 #include <stdio.h> #include <stdlib.h> #include <sys/time.h> #include <pthread.h> #define MATRIX 6400 #define THREAD 2 #define COUNT 30 #define SPLIT 100 int INDEX = 0; double a[MATRIX * MATRIX], b[MATRIX], x[MATRIX]; pthread_mutex_t m1; double gettimeofday_sec() { struct timeval tv; gettimeofday(&tv, NULL); return tv.tv_sec + (double)tv.tv_usec*1e-6; } void thread_func(void *arg) { int i, j, tmp; while(INDEX < MATRIX) { pthread_mutex_lock(&m1); tmp = INDEX; INDEX += SPLIT; pthread_mutex_unlock(&m1); for(i = tmp; i < tmp + SPLIT; i++) { for(j = 0; j < MATRIX; j++) { b[i] += a[i * MATRIX + j] * x[j]; } } } } int main() { int i, j; double timeA, timeB; pthread_t handle[THREAD]; pthread_mutex_init(&m1, NULL); for(i = 0; i < MATRIX * MATRIX; i++) a[i] = rand() % 10; for(i = 0; i < MATRIX; i++) x[i] = rand() % 10; timeA = gettimeofday_sec(); //計測開始 for(i = 0; i < COUNT; i++) { for(j = 0; j < THREAD; i++) pthread_create(&handle[i], NULL, (void *)thread_func, NULL); for(j = 0; j < THREAD; i++) pthread_join(handle[i], NULL); INDEX = 0; } timeB = gettimeofday_sec(); //計測終了 printf("計算時間:%d\n", timeB - timeA); return 0; } cygwinでコンパイル、実行すると Exception: STATUS_ACCESS_VIOLATION at eip=00401276 eax=000018D0 ebx=000018FF ecx=00000003 edx=0022CE64 esi=611021A0 edi=004015E8 ebp=0022CCE8 esp=0022CC90 program=C:\cygwin\home\管理者\a.exe, pid 2020, thread main cs=001B ds=0023 es=0023 fs=003B gs=0000 ss=0023 Stack trace: Frame Function Args 0022CCE8 00401276 (00000001, 6116B690, 13F40090, 0022CC70) 0022CD98 610060D8 (00000000, 0022CDD0, 61005450, 0022CDD0) 61005450 61004416 (0000009C, A02404C7, E8611021, FFFFFF48) 7 [main] a 2020 _cygtls::handle_exceptions: Error while dumping state (probably corrupted stack) という内容のstackdumpファイルが生成されて実行できません。 どのように修正すればうまく実行できるでしょうか? 環境は OS:WindowsXP SP3 CPU:Intel(R) Core(TM)2 Duo E4500 @2.20GHz RAM:2048MB です。 よろしくお願いします。

  • c言語でDFTのプログラムを作成したのですが

    c言語でDFTのプログラムを作成しました。 以下にソースを載せます。 #include<stdio.h> #include<math.h> #include<stdlib.h> #include<time.h> #define PI 3.141592653589793 #define N 64 //データ数 DFT(double result[]){ int i,k; double A[N],B[N],T=0; //A[N]:実数部,B[N]:虚数部 double a,b; for(k=0;k<N;++k){ a=b=0; for(i=0;i<N;++i){ a=a+result[i]*cos(2*PI*i*k/N);      b=b+(-1.0)*result[i]*sin(2*PI*i*k/N); } A[k]=a/N; B[k]=b/N; } for(i=0;i<N;++i){ printf("[%f秒]:Re:%f,Im:%f\n",T,A[i],B[i]); //変換後の値を表示 T=T+(0.1/N); } } main(){ int i; double T=0; double Sampdata; double result[N]; for(i=0;i<N;++i){ Sampdata=5*sin(20*PI*T);      //0~0.1秒間をN個にサンプリング result[i]=Sampdata; //サンプリングデータを代入 T=T+(0.1/N); } clock_t start,end; //処理時間計測開始 start=clock(); DFT(result); end=clock(); printf("%.2f秒かかりました\n",(double)(end-start)/CLOCKS_PER_SEC); //処理時間表示 } 元信号には5sin(20πt)の値を入れています。この信号は周期は0.1secです。 これでフーリエ変換を行うとデータ数N/2を中心に対称なデータが出てくるのですが、処理が終わるのが早い気がするんです。 例えば2^15個のデータで実行しても2分もかからずに処理が終わってしまいます。一応、対称性が出てるとはいえ、終わるのが早すぎる気がするのですが、おかしい所があれば教えていただけると嬉しいです。 よろしくお願いします。

  • 計算処理時間を出力したい!

    素因数分解を行うプログラムにおいて、処理時間を計算する必要があります。 #include <stdio.h> #include <time.h> main() unsigned long i,t0,t1; t0 = clock(); for(i=0; i<100000; i++){ } t1 = clock(); printf("Time : %lf\n", t1 - t0); } などと例を作ってテストしているのですが、小さな単位まで出てきません。 100分の1秒単位で出てきているとおもいます。 もっと細かい時間を計測するのにはどうしたらいいのでしょうか?

  • C言語:計算問題を解く時間が計測できません

    C言語を学び始めて1週間程度のものです。 現在柴田望洋著の明解C言語中級編という本でC言語を学んでいます。 その中のプログラミング例を真似してプログラミングしているのですが、 うまく動作しません。詳細は以下の通りです。 著書のList2-6のプログラミングです。 問題:計算問題を解く時間を計測が0.0秒になってしまう。 ここよりプログラミングです。 #include <time.h> #include <stdio.h> #include <stdlib.h> int main (void) { int a, b, c; int x; clock_t start, end; double req_time; srand(time(NULL)); a = 10 + rand() % 90; b = 10 + rand() % 90; c = 10 + rand() % 90; printf("%d + %d + %dは何ですか:", a, b, c); start = clock(); while (1) { scanf("%d", &x); if (x == a + b +c) break; printf("\a違いますよ!!\n再入力してください:"); } end = clock(); req_time = (double)(end - start) / CLOCKS_PER_SEC; printf("%.1f秒かかりました。\n", req_time); if (req_time > 30.0) printf("時間がかかりすぎです。\n"); else if (req_time > 17.0) printf("まあまあですね。\n"); else printf("素早いですね\n"); return (0); } このプログラムを実行して計算を解いて正解の答えを入力しても 0.0秒かかりました。 素早いですね。 としかでてきません。どうすればきちんと時間を計測するプログラミングができるでしょうか。 パソコンはMacbookairを使っています。 コンパイラ(?)はXcodeというものを使っていると思います(ここらへんは勉強不足でよくわかりません。) もしよければご回答お願いします。

  • C言語

    【プログラム】 #include<stdio.h> int main (void) { int i,n; long a; scanf("%d",&n); a=1; for(i=1;i<=n;i++){ printf("%3d回目 %12ld\n",i,a); a=a*2; } return 0; 【実行結果】("33"と入力) 33 1回目      1 2回目      2 3回目      4 4回目      8  :        :  :        : 31回目 1073741824 32回目 -2147483648 33回目      0 【質問】 2倍していくと、32回目に負の数になり さらに33回目には0になりました。 こうなる理由を教えてください。 私は高2です。 出来ればわかりやすくお願いします。

  • C言語の実行について、

    #include <stdio.h> #define N 2 void main(void) { int i ,j ; for( i=1 ; i <= N ; ++i) { for( j=i ; j < N+2 ; ++j) { printf("j=%d\n",j); } printf("i=%d\n",i); } } を実行すると、 j=1,j=2,j=3,i=1,j=2,j=3,i=2となったんですが、 どういった順序で行われているのでしょうか? よろしくお願いします。

  • C言語

    forの直後で1+2+3+4+5+・・・・・・・と加算し続ける式がわからないので教えてください。 #include<stdio.h> int main(void) { char moji; int i,sum; printf("正の整数を1から順に加算します。n\"); printf("加算を開始してよろしいですか。(Y=実行。N=終了)\n"); moji=getchar(); if(moji==y) { for(i=2;sum>=1001;i++) { この部分がわかりません; printf("加算値は%dです。¥n",sum); } }else if(moji=='n'){ printf("終了します。\n"); }else{ printf("YまたはNを入力してください。\n"); } return 0; }

  • C言語に直して下さい

    VisualC++で円周率を求めるプログラムなのだそうですが、 自分はC言語しか使ったことがないため、よく分かりません。 Cでコンパイルできるように直していただけないでしょうか。 よろしくお願いします。 #include <stdio.h> #include <stdlib.h> #include <string.h> #define N 21 #define K 100000 void add(unsigned long a[],unsigned long b[]) { int c = 0, tmp; for (int i = N - 1; i > -1; i--) { tmp = a[i] + b[i] + c; a[i] = tmp % K; c = tmp / K; } } void sub(unsigned long a[],unsigned long b[]) { int c = 0, x = 0; for (int i = N - 1; i > -1 ; i--) { x = c; if (a[i] < b[i] + x ) c = 1; else c = 0; a[i] = c * K + a[i] - b[i] - x; } } void div(unsigned long a[], unsigned long x) { int c=0, tmp; if (x >= K) { printf("Div Error\n"); getchar(); exit(1); return; } for (int i = 0; i < N ; i++) { tmp = (a[i] + c * K) / x; c = (a[i] + c * K) % x; a[i] = tmp; } } void clear(unsigned long a[]) { memset(a,0x00,sizeof(a)*N); } void set(unsigned long a[], unsigned long b[]) { memcpy(a,b,sizeof(a)*N); } void set(unsigned long a[], unsigned long b) { if (b<K) { clear(a); a[0]=b; } } int _tmain(int argc, _TCHAR* argv[]) { unsigned long pai[N], fn[N], gn[N], tmp1[N], tmp2[N]; int i; unsigned long n; clear(pai); clear(fn); clear(gn); clear(tmp1); clear(tmp2); set(fn, 16*5); set(gn, 4*239); for(n=0;n<40000;n++) { div(fn, 25); div(gn, 239); div(gn, 239); set(tmp1, fn); div(tmp1, 2*n+1); set(tmp2, gn); div(tmp2, 2*n+1); if (n%2==0) { add(pai, tmp1); sub(pai, tmp2); }else{ add(pai, tmp2); sub(pai, tmp1); } } for (i=0;i<N;i++) { printf("%5lu ", pai[i]); } getchar(); return 0; }

専門家に質問してみよう