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

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

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

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

アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

Q&A

解決済

5回答

339閲覧

ある配列における各値の1の位の合計を計算するためのコードの比較

apeirogon0813

総合スコア117

C

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

アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

0グッド

0クリップ

投稿2019/03/12 11:35

編集2019/03/12 11:44

ある配列における各値の1の位の合計を計算するために2つのコード

C

1for(i=0; i<num; i++) 2 sum += a[i] % 10;

C

1for(i=0; i<num; i++) { 2 if(a[i] >= 10) 3 sum += a[i] % 10; 4 else 5 sum += a[i]; 6}

を考えたのですが、 どちらの方がコーディング力は良いのでしょうか。

後者に比べると前者は各値が10以上でなくても、つまり全ての値に対し"% 10"として合計に加えているので
無駄が多い気もしますが後者みたいに場合分けをするよりコードが単純で美しい気がします。

追記
また、各値の桁の数を足し合わせてから、合計を計算する場合、前者の方法では

C

1for(i=0; i<num; i++) 2 sum += a[i] % 10 + (a[i] % 100) / 10 + (a[i] % 1000) / 100..... ;

となり、もし値が1桁の場合だと計算が余分に多くなってしまい場合分けした方がいいとも思われますが場合によるのでしょうか。

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

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

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

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

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

cateye

2019/03/12 11:42

if(a[i] <= 10) って、if(a[i] >=10)の間違いでは?
apeirogon0813

2019/03/12 11:44

ありがとうございます。修正いたしました。
guest

回答5

0

一般論としては、分岐が少ない方が、テストケースが少なくなって、言い換えると、バグが入り込みにくくて、良いプログラムです。

1000万回のループの内側とかで無い限り、ごく僅かな実行時間の差は気にしません。

投稿2019/03/12 13:11

otn

総合スコア84557

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

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

apeirogon0813

2019/03/12 13:14

ありがとうざいます。丁寧すぎる分岐はダメなんですね。
otn

2019/03/13 00:13

分岐を少なくする事が目的化しちゃって、トリッキーなコードも駄目ですけどね。
guest

0

ベストアンサー

実測してみましょう。以下のような簡単なプログラムを作って試してみました。

C

1#include <stdio.h> 2#include <sys/time.h> 3 4#define N 100000 5 6double getTime(); 7 8int main() 9{ 10 double t0; 11 12 int i; 13 int sum; 14 int a[N]; 15 16 for (i = 0; i < N; i++) { 17 /* a[i] = i; */ 18 a[i] = i % 10; 19 } 20 21 t0 = getTime(); 22 for (i = 0; i < N; i++) { 23 sum += a[i] % 10; 24 /* */ 25 /* if (a[i] > 10) { */ 26 /* sum += a[i] % 10; */ 27 /* } else { */ 28 /* sum += a[i]; */ 29 /* } */ 30 /* */ 31 } 32 printf("%d %f\n", sum, getTime() - t0); 33} 34 35double getTime() { 36 struct timeval tv; 37 38 gettimeofday(&tv, NULL); 39 return tv.tv_sec + 1e-6 * tv.tv_usec; 40}

家のMacで試したところ以下のような結果です。

ifなしifあり
1から1000000.25ms0.31ms
全部10以下0.25ms0.17ms

結果から考えると以下のようなことが言えるのではないかと思います。

  • ifを使わない方は配列の内容によらず一定時間
  • ifを使うと10以下の要素の割合が少なければifの分だけ遅くなるが、10以下の要素が多ければ%の計算がいらない分速くなる
  • ifより%演算の方が2.3倍ぐらい時間がかかる
  • 10以下の要素の割合が57%ぐらいのところでどちらが速いかが逆転すると予想される

このくらいの違いだとif使わない方が単純でいいでしょう。

ただし結果はCPUやコンパイラなどの条件でかわってくるところではあると思います。

たとえば昔の8bit CPUだと割り算がCPUでサポートされてなくてとてつもなく遅かったりするのでそういうときは複雑になってもifを使う価値があるかもしれません。

投稿2019/03/12 12:58

crhg

総合スコア1175

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

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

apeirogon0813

2019/03/12 15:06

具体的にありがとうございます!やはりif文を使わない方が良さそうですね!明確な根拠をありがとうございます。
guest

0

c

1for(i=0; i<num; i++) 2 sum += a[i] % 10;

は短くてよいと思います。
でも、次のようなコードは如何でしょう?

c

1#include<stdio.h> 2 3// 配列の要素を1の位だけに変換する 4int *conv_mod10(int * a, unsigned int n) { 5 int * end = a + n; 6 for(int * p = a; p < end;) {*p++ %= 10;} 7 return a; 8} 9 10// 配列の合計を計算する 11int array_sum(int * a, unsigned int n) { 12 int sum = 0; 13 int * end = a + n; 14 for(int * p = a; p < end;) {sum += *p++;} 15 return sum; 16} 17 18int main() { 19 int a[] = {1, 11, 21}; 20 unsigned int size = sizeof(a) / sizeof(int); 21 22 int sum = array_sum(conv_mod10(a, size), size); 23 printf("sum = %d\n", sum); 24}

ループが2回回ってしまいますが、
一の位だけを取り出すことと、それを合計することが分離されています。
また配列の要素へのアクセスは、添字を使わずにポインターを使ってみました。
(コンパイラーの最適化のことを考えれば意味が無いかもしれませんが)

投稿2019/03/12 13:56

katoy

総合スコア22324

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

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

apeirogon0813

2019/03/12 15:10

ありがとうございます。このようなやり方もあるのですね。参考になりました。
guest

0

どちらの方がコーディング力は良いのでしょうか。

コーディング力とは何でしょうか?
まず、ここからでしょうか。

今時のPCなら、誤差かも知れませんが、古いCPUだと、if文のコストは大きいので、自分にとって、後者はダメですね。

if文のコスト: 条件を判定し、必要によって分岐を行う。古いCPUだと通常の演算に較べ、数倍の時間を必要とする。

また、コードも 2 → 5行になっている。(可読性が落ちる)

投稿2019/03/12 11:49

pepperleaf

総合スコア6383

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

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

guest

0

後者は無駄ですね
if文を無駄に繰り返してるとみれます

投稿2019/03/12 11:38

y_waiwai

総合スコア87774

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

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

apeirogon0813

2019/03/12 11:44

やはりそうなんですね。追記の場合だといかがでしょうか。
y_waiwai

2019/03/12 11:50

各桁の足し合わせの部分もループでさせましょうよ while(a>0){ sum+=a%10; a/=10;}
apeirogon0813

2019/03/12 12:44

ありがとうございます。参考にします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問