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

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

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

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

Q&A

解決済

4回答

1523閲覧

平均値、分散値、最大値、最小値、偏差値を求める

mudannkesseki

総合スコア16

C

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

0グッド

0クリップ

投稿2018/09/18 16:11

編集2018/09/19 00:59

コンパイルはできましたが、うまく作動されません。

・任意の数を任意の個数だけ入力する。0を入力すると入力終了するようにする。
・入力した数を配列を利用し、平均値、分散値、最大値、最小値、偏差値を求める。

がお題です。
今うまくいっているのは最大値だけで、最小値は一番最後に入力した数が出力されます。

発生している問題・エラーメッセージ

例えば、1,2,3と入力したとすると、

最大値3、最小値3、平均値分散値偏差値は、-1.#QNANO と表示されます。どこがおかしいか見ていただきたいです。

該当のソースコード

C言語

1 2#include <stdio.h> 3#include<math.h> 4 5int main() 6{ 7 8 float z,x[100],max,min,heikin,bunsan,hensa,hensati; 9 int cnt,i,gokei,kosu; 10 11 i=0; 12 cnt=0; 13 max=x[i]; 14 min=x[i]; 15 while(i<100){ 16 scanf("%f",&z); 17 if(z==0)break; 18 x[i]=z; 19 cnt++; 20 printf("Input(%d): %.6f \n",i,x[i]); 21 22 23 if(x[i]>max){ 24 max=x[i]; 25 } 26 if(x[i]<min || x[i]!=0){ 27 min=x[i]; 28 } 29 30 i++; 31 } 32 33 34 35 gokei=0; 36 kosu=0; 37 for(i=0;i<100;i++){ 38 gokei+=gokei+x[i]; 39 kosu++; 40 } 41 heikin=gokei/kosu; //平均値 42 43 for(i=0;i<100;i++){ 44 bunsan+=((x[i]-heikin)*(x[i]-heikin))/kosu; 45 } 46 47 printf("heikin = %.6f ",heikin); 48 printf("max = %.6f ",max ); 49 printf("min = %.6f ", min ); 50 printf("sigma = %.6f \n",bunsan ); 51 52 for(i=0;i<cnt;i++){ 53 hensa=x[i]-heikin; 54 hensati=((hensa/sqrt(bunsan))+10)+50; 55 printf("%d : hensati = %.6f \n",i,hensati); 56 } 57 58 return 0; 59}

### 補足

   分散^2=Σ(注目している値ー平均値)^2/入力値の個数

   偏差=注目している値ー平均値
偏差値=(偏差/分散の平方根)×10+50

    で求められます。

補足情報(FW/ツールのバージョンなど)

学習用C言語開発環境を使用しています。

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

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

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

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

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

kei344

2018/09/18 16:24

質問タグがCSSのプロパティになっているので、「C」などにしたほうがよいのでは。
mudannkesseki

2018/09/18 16:28

有難うございます。編集しようと思ったのですがやりかたが分からず、、、分かり次第すぐに修正いたします!
guest

回答4

0

C言語とのことなので、C++ の機能は仕様せず、書いてみました。
c++ の標準ライブラリを使うと、もう少し完結にかけます。

最小値を計算する

初期値は float 型のとり得る最大の値 FLT_MAX にすればよいです。

c

1/** 2 * @brief 配列の最小値を計算する。 3 * @param array 配列 4 * @param n 配列の長さ 5 * @return 配列の最小値 6 */ 7float min(float array[], int n) 8{ 9 if (n == 0) // 配列が空の場合 10 return 0; 11 12 float min = FLT_MAX; 13 for (int i = 0; i < n; i++) { 14 if (min > array[i]) 15 min = array[i]; 16 } 17 18 return min; 19}

最大値を計算する。

初期値は float 型のとり得る最小の値 -FLT_MAX にすればよいです。

c

1/** 2 * @brief 配列の最大値を計算する。 3 * @param array 配列 4 * @param n 配列の長さ 5 * @return 配列の最大値 6 */ 7float max(float array[], int n) 8{ 9 if (n == 0) // 配列が空の場合 10 return 0; 11 12 float max = -FLT_MAX; 13 for (int i = 0; i < n; i++) { 14 if (max < array[i]) 15 max = array[i]; 16 } 17 18 return max; 19}

平均、分散、標準偏差を計算する。

  • 平均μ = Σ x_i / 入力値の個数
  • 分散σ = Σ(x_i - μ)^2 / 入力値の個数
  • 標準偏差 = √σ

分散については、分散σ = Σx_i^2 / 入力値の個数 - μ^2 と式変形でき、平均及び分散両方を計算する際には、こちらのほうが計算量が少なくてすみます。

ステップとしては、

  1. 和 Σx_i、自乗和 Σx_i^2 を計算する。
  2. μ = Σx_i / n で平均を計算する。
  3. σ^2 = Σx_i^2 / n - μ^2 を計算する。
  4. √σ^2 を計算する。

c

1/** 2 * @brief 配列の平均、分散及び標準偏差を計算する。 3 * @param array 配列 4 * @param n 配列の長さ 5 * @param mean 配列の平均 6 * @param var 配列の分散 7 * @param std 配列の標準偏差 8 */ 9void mean_var(float array[], int n, float *_mean, float *_var, float *_std) 10{ 11 if (n == 0) { // 配列が空の場合 12 *_mean = *_var = *_std = 0; 13 return; 14 } 15 16 // 配列の和および自乗和を計算する。 17 float sum = 0; // 和 18 float squared_sum = 0; // 自乗和 19 for (int i = 0; i < n; i++) { 20 sum += array[i]; 21 squared_sum += array[i] * array[i]; 22 } 23 24 // 平均、分散、標準偏差を計算する。 25 float mean = sum / n; 26 float var = (squared_sum / n - mean * mean); 27 float std = sqrt(var); 28 29 // ポインタ経由で値を返す。 30 *_mean = mean; 31 *_var = var; 32 *_std = std; 33}

偏差値を計算する。

  • 偏差値 = (x - μ) / σ x 10 + 50

c

1 2/** 3 * @brief 偏差値を計算する。 4 * @param array 配列 5 * @param n 配列の長さ 6 * @param mean 配列の平均 7 * @param std 配列の標準偏差 8 * @param std_scores 配列の各要素の偏差値 9 */ 10void std_scores(float array[], int n, float mean, float std, float std_scores[]) 11{ 12 if (n == 0) // 配列が空の場合 13 return; 14 15 for (int i = 0; i < n; i++) { 16 std_scores[i] = 10 * (array[i] - mean) / std + 50; 17 } 18} 19

コード全体

#undef NDEBUG // assert をリリースビルドで実行するため #include <assert.h> #include <float.h> #include <math.h> #include <stdio.h> /** * @brief 配列の最小値を計算する。 * @param array 配列 * @param n 配列の長さ * @return 配列の最小値 */ float min(float array[], int n) { if (n == 0) // 配列が空の場合 return 0; float min = FLT_MAX; for (int i = 0; i < n; i++) { if (min > array[i]) min = array[i]; } return min; } /** * @brief 配列の最大値を計算する。 * @param array 配列 * @param n 配列の長さ * @return 配列の最大値 */ float max(float array[], int n) { if (n == 0) // 配列が空の場合 return 0; float max = -FLT_MAX; for (int i = 0; i < n; i++) { if (max < array[i]) max = array[i]; } return max; } /** * @brief 配列の平均、分散及び標準偏差を計算する。 * @param array 配列 * @param n 配列の長さ * @param mean 配列の平均 * @param var 配列の分散 * @param std 配列の標準偏差 */ void mean_var(float array[], int n, float *_mean, float *_var, float *_std) { if (n == 0) { // 配列が空の場合 *_mean = *_var = *_std = 0; return; } // 配列の和および自乗和を計算する。 float sum = 0; // 和 float squared_sum = 0; // 自乗和 for (int i = 0; i < n; i++) { sum += array[i]; squared_sum += array[i] * array[i]; } // 平均、分散、標準偏差を計算する。 float mean = sum / n; float var = (squared_sum / n - mean * mean); float std = sqrt(var); // ポインタ経由で値を返す。 *_mean = mean; *_var = var; *_std = std; } /** * @brief 偏差値を計算する。 * @param array 配列 * @param n 配列の長さ * @param mean 配列の平均 * @param std 配列の標準偏差 * @param std_scores 配列の各要素の偏差値 */ void std_scores(float array[], int n, float mean, float std, float std_scores[]) { if (n == 0) // 配列が空の場合 return; for (int i = 0; i < n; i++) { std_scores[i] = 10 * (array[i] - mean) / std + 50; } } int main() { float array[100]; // 入力した数字を格納する配列 float input; // 入力を格納する変数 int n; // 入力した数字の数 while (n < 100) { printf("Input (%d): ", n); scanf("%f", &input); if (input == 0) break; // 入力終了 array[n++] = input; printf("%.2f\n", input); } float minval = min(array, n); // 最大値を計算する。 float maxval = max(array, n); // 最小値を計算する。 float mean, var, std; mean_var(array, n, &mean, &var, &std); // 平均、分散、標準偏差を計算する。 float scores[100]; std_scores( array, n, mean, std, scores); // 配列の各要素の偏差値を計算する。 printf( "min: %.2f, max: %.2f, mean: %.2f, var: %.2f, std: %.2f\n", minval, maxval, mean, var, std); printf("std scores: "); for (int i = 0; i < n; i++) { printf("%.2f ", scores[i]); } printf("\n"); // テスト ////////////////////////////////////////////////// // テストデータ array[0] = 1.1; array[1] = 2.5; array[2] = 4.2; array[3] = 1.5; // 最小値、最大値、平均、分散、標準偏差、偏差値を計算する。 minval = min(array, 4); maxval = max(array, 4); mean_var(array, 4, &mean, &var, &std); std_scores(array, 4, mean, std, scores); // 正解の値と合っているか確認する。 assert(fabs(minval - 1.1) < 0.01); assert(fabs(maxval - 4.2) < 0.01); assert(fabs(mean - 2.325) < 0.01); assert(fabs(var - 1.431) < 0.01); assert(fabs(std - 1.196) < 0.01); float expected_scores[] = {39.76, 51.46, 65.66, 43.10}; for (int i = 0; i < 4; i++) { assert(fabs(scores[i] - expected_scores[i]) < 0.01); } return 0; }

投稿2018/09/20 05:42

tiitoi

総合スコア21956

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

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

mudannkesseki

2018/09/21 01:46

とてもご丁寧にありがとうございます。分散の計算方法を参考にさせていただきました。ありがとうございました!
guest

0

ベストアンサー

はじめての回答になるので、わかりにくところもあると思いますが宜しくお願い致します。

・最大値最小値
方針が変わってしまうので、もしかしたら不採用になってしまうかもしれませんが、
配列に与えられた数をソートしてから
配列の最初の数と配列の最後の数を表示すればよいと思います。

ソートの書き方については「C言語 ソート」とかでググるとすぐにでてきます。

・平均値
入力した配列の数に関わず100回繰り替えされているので、合計を必ず100で割ることになっています。
そもそも合計に関しても変なところがあるのですが、文字では説明しにくいので。。。

こちらも「C言語 配列 合計」「C言語 配列 平均値」とかでググると出ます

・分散や偏差値
平均値がおかしい状態になっているので今は書きません

・全体的に
いきなり長い文章の関数を作成するよりも、
配列に数値を入力する関数、最大値最小値を出力する関数を作成、平均値を出力する関数を作成という練習をやっていったほうがいいのかなと思います。

私もまだまだ初心者ですので(質問を見るとバレます)あてにならないかもと思われるかもしれませんが、参考にしていただければ幸いです。

投稿2018/09/20 02:39

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

mudannkesseki

2018/09/21 01:44

大変わかりやすかったです!おかげさまでプログラム完成しました。本当にありがとうございます!
退会済みユーザー

退会済みユーザー

2018/09/21 02:23

ありがとうございます! 私利私欲なのですが、ベストアンサーにして頂けると嬉しいです。。。!
guest

0

処理のナカミまではみてませんが。

関数内で定義するローカル変数は初期化されないのでその内容は不定となります
なので、

max=x[i];

min=x[i];

max、minのナカミは不定です

if(x[i]<min || x[i]!=0){

if(x[i]!=0){
と同じ動作となりますが、これは意図した動作でしょうか

Windowsでやってるなら、VisualStudioを使いましょう。
ソースの任意の行で実行を止め、変数のナカミを参照することができます
また、変数のナカミを見ながら1行づつ実行させることもできます
そうやって自分のコードをデバッグしていけばどうでしょうか
いまのようにわけも分からずに当てずっぽでコードを書かなくて済みます

投稿2018/09/18 23:57

y_waiwai

総合スコア87774

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

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

mudannkesseki

2018/09/19 03:54

有難うございます。maxとminの初期化の仕方がよくわかりません。whileの中にいれると最大最小どちらも一番最後に入力した値になってしまいました。 if(x[i]<min || x[i]!=0) は、最後0を入力したときにその値を認識しているのか、最小値が0になってしまうので入れてみたのですが...。 VisualStudioで、少しづつデバッグする方法を調べてみたのですが、ソースの途中にブレークポイントを設置というのはなんというコマンドを打てばいいのでしょうか。
yukihisa

2018/09/19 04:00 編集

初期化は0にしておいて入力一発目の値を無条件でmaxとminに入れればよかですよ。
y_waiwai

2018/09/19 05:00

関数の中で配列定義するんじゃなく、関数の外で定義すれば(グローバル変数とすれば)、その内容はゼロに初期化されます とにかく、まずはVisualStudioを入れてみましょう。
guest

0

max,min の初期設定で、入力前の x[0] を使用してはいけない。

if(x[i]<min || x[i]!=0){
は、x[i] は 0 でないから、必ず true になってしまいます。
&& か、どうせ 0 では無いので x[i]!=0 の部分をのけるかですかね。

for(i=0;i<100;i++){
は、入力が途中で終わっていても100回繰り返してしまいます。
何のために cnt で入力個数を数えたんですか?

投稿2018/09/18 20:06

PingHermit

総合スコア478

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問