質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

4回答

2713閲覧

clock関数を使った問題

deadline444

総合スコア11

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

0クリップ

投稿2017/01/18 01:53

int型の変数どうしの積とdouble型の変数どうしの掛け算1回あたりの実行時間を10万~1000万回程度と多数回繰り返し計算するのに要する時間の総和から演算以外の部分(繰り返しや代入)にかかる時間を除外して純粋に積演算にかかる時間を推定するプログラムを作成し,それぞれの実行時間の比較を行うという問題です。
結果が負になってしまいます。どこを改善すればよいでしょうか?
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int
main(void)
{
clock_t cl1, cl2, cl3, cl4, cl5, cl6, cl7, cl8;
int i, s;
double j, p;
/全体(int)/
cl1 = clock();
for (i = 0; i < NLOOP; i++) {
s = i * i;
}
cl2 = clock();

/代入, 繰り返し(int)/
cl3 = clock();
for (i = 0; i < NLOOP; i++) {
s = i;
}
cl4 = clock();

printf("int型の掛け算のみにかかる時間%f [μs]\n",( ((double)(cl2 - cl1) / CLOCKS_PER_SEC) - ((double)(cl4 - cl3) / CLOCKS_PER_SEC) ) * 100);

/全体(double)/
cl5 = clock();
for (j = 0; j < NLOOP; j++) {
p = j * j;
}
cl6 = clock();

/代入, 繰り返し(double)/
cl7 = clock();
for (j = 0; j < NLOOP; j++) {
p = j;
}
cl8 = clock();

printf("double型の掛け算のみにかかる時間%f [μs]\n",( ((double)(cl6 - cl5) / CLOCKS_PER_SEC) - ((double)(cl8 - cl7) / CLOCKS_PER_SEC) ) * 100);

return 0;
}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

ベストアンサー

そもそも考え方が違くないですか?
代入の総時間から積演算の総時間を引いたら、そりゃマイナス値にもなるでしょう(代入の方が軽いから)
処理は4つある。
int型の積演算
int型の代入
double型の積演算
double型の代入
で、積演算については、ループ処理を除いた純粋な演算部分のみの時間を求める。
代入については、ループ処理を除いた純粋な演算部分のみの時間を求める。
つまり、ロジックとしてはこうじゃないでしょうか(時間部分は簡略してmsにしています)

c

1cl = 0; 2for (i = 0; i < NLOOP; i++) { 3 cls = clock(); 4 s = i * i; 5 cle = clock(); 6 cl += (cle - cls); 7} 8printf("演算のみ %ldms\n", cl);

上記はint型の積演算部分のみですが、他の3つについても同様の考え方です。

投稿2017/01/18 04:00

編集2017/01/18 04:38
ttyp03

総合スコア16998

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

deadline444

2017/01/18 23:38

成る程分かりました。 ありがとうございます。
catsforepaw

2017/01/19 01:03

ベストアンサーが付いた後で申し訳ないのですが、論理的には正しいように思えますが、実際にはそれでは正確には計測できません。一般に出回っているPCでマシンサイクル単位で時間が計測できる処理系はおそらく存在しないと思います。`clock`関数が返す値は、Linux(gcc)ならマイクロ秒、Windows(VC++)ならミリ秒単位です。したがって、`s = i * i`1回分の時間を計測することは不可能です。また、`clock`関数の呼び出し自体が掛け算と比べればそれにかかる時間など無視できるぐらいに遅いので、仮に計測できたとしても、それは`clock`関数の処理時間ということになってしまいます。
ttyp03

2017/01/19 01:08 編集

技術的にはおっしゃる通りだと思いますが、あくまでも何かの課題(問題)なので、そこまで技術的なことを求めているのではないと思います。 正確には測れないかもしれないけど、ロジック的にはどう考えればいいの?くらいの課題と読み取り回答しました。
ttyp03

2017/01/19 01:10

もちろん質問者様が、「そんな簡単なことではない」「きちんと正確に測りたいんだ」というなら他の回答を参考に実装していただければ良いです。
deadline444

2017/01/19 02:29

丁寧にありがとうございます。
catsforepaw

2017/01/19 04:10

ttyp03 さん > あくまでも何かの課題(問題)なので であるなら、質問文を読む限り、やはり基本的な考え方は質問者さんのコードで正しいと思うのですが……。
ttyp03

2017/01/19 04:14

質問者様のコードは、 (ループ処理を含む積演算の総時間)-(ループ処理を含む代入処理の総時間) を算出めています。 それがどうして問題文にある「純粋に積演算にかかる時間」になるのでしょうか。
catsforepaw

2017/01/19 04:38

ttyp03 さん > それがどうして問題文にある「純粋に積演算にかかる時間」になるのでしょうか。 同じ条件で両者の時間を計測した場合、その差分が処理の違いによる差分と考えるのは理にかなっていると思います。 また、問題文には「多数回繰り返し計算するのに要する時間の総和」と書かれていますので、ループの開始から終了までの時間を計測すると考えるのが自然です。それに「演算以外の部分(繰り返しや代入)にかかる時間を除外して」という文言からも、計測の範囲にはfor文も含まれると考えられます。 出題者は、問題を解かせる以上、実際に検証できなければ困るわけで、検証不可能な回答にはならないだろうというのが私の考えです。
ttyp03

2017/01/19 04:49

論理で考えれば確かに質問者様のコードでも正しいような気はしてきました。 要は、 (ループ処理を含む積演算の総時間)-(ループ処理を含む代入処理の総時間) ではなく、 (ループ処理を含む積演算と代入処理の総時間)-(ループ処理を含む代入処理の総時間) だから、積演算部分のみの時間が計算できるという理論ですね。今わかりました(すみません) だとしても結局は他の回答にあるように細かいチューニングをしないと正しく計測できないわけですから、課題程度にそこまで求めているんでしょうか。 こればかりは出題者に聞くしかないですが。
guest

0

時間計測の誤差により、s = i * i(p = j * j)の方の時間よりもs = i(p = j)の方の時間が上回ったためです。
実際のところ、今時のCPUは掛け算の演算速度が非常に速いので、for文と変数への代入の処理にかかる時間に比べれば誤差程度にしかなりません。その誤差がたまたま後者で上回ると、当然のことながら結果は負数になってしまいます。

この手の計測をする場合、できるだけ誤差の要素を減らすためにfor文の中の処理を1回だけでなく複数回(10回とか)実行させることが多いです。

こんな感じ

/*全体(int)*/ cl1 = clock(); for (i = 0; i < NLOOP; i++) { s = i * i; s = i * i; s = i * i; s = i * i; s = i * i; s = i * i; s = i * i; s = i * i; s = i * i; s = i * i; } cl2 = clock(); /*代入, 繰り返し(int)*/ cl3 = clock(); for (i = 0; i < NLOOP; i++) { s = i; s = i; s = i; s = i; s = i; s = i; s = i; s = i; s = i; s = i; } cl4 = clock();

※最適化オプションは考慮していません。

投稿2017/01/18 02:50

catsforepaw

総合スコア5938

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

単純に、「誤差の範囲よりかかる時間が少ない」だけではないかと思います。

多くのOSはマルチタスクですので、裏で動く処理の加減などで、全く同じプログラムでも所要時間は変化します。

そして、x64ではSSE2までが標準命令に入り、浮動小数点数ですら乗算のスループットは2クロックというレベルです(Intelの資料PDF)。

ということで、「乗算の速度」は想像を絶する回数を測定しないと、有意な結果は得られないと思います。

投稿2017/01/18 02:22

maisumakun

総合スコア145183

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

こんにちは。

もし、リリース・ビルドされているのでしたら、最適化されてs=i*i;等の計算が最後だけしか行われていないかも知れません。
sやpにvolatileをつければ最適化を抑止できます。

投稿2017/01/18 02:19

Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問