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

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

ただいまの
回答率

88.81%

C言語 偏差値を求める問題

解決済

回答 2

投稿

  • 評価
  • クリップ 1
  • VIEW 2,399

mikan_555

score 15

C言語 偏差値を求める問題

0-10点の間でランダムに点数を発生させて平均値、最高値、標準偏差を求め、点数をソートして表示させるプログラムをc言語で作っています。

エラーメッセージは出ていないのですが、偏差値を正しく出力できません。
原因を教えていただきたいです。よろしくお願いします。

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

3点 4点 10点 の偏差値がほぼ等しくなってしまうなど、正しく表示することができません。

実行結果


score,standard score
2    32.679492
3    55.772837
4    55.772879
10    55.774792
max: 10
ave: 4.750000

該当のソースコード

偏差値を求める関数 calc_deviation_score()

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>

void set_array_rand(int n, int* score);
int find_max_in_array(int n, int* score);
double calc_ave(int n, int* score);
int calc_sum(int n, int* score);
void swap(int *a, int *b);
void bubble_sort(int n, int *score);
void print_array(int n, int* a);
double calc_deviation_score(int n, int* score, int ten);

#define N 4

int main(void)
{
  int i, id, max ;
  int score[N];
  double ave;

  printf("score,standard score \n");


  set_array_rand(N, score);
  bubble_sort(N, score);    /* sort here */
  print_array(N, score);


  id = find_max_in_array(N, score);
  max = score[id];
  ave = calc_ave(N, score);
  printf("max: %d \n", max);
  printf("ave: %f \n", ave);

}


/*random score */
void set_array_rand(int n, int* score)
{
  int i;
  srand((unsigned int)time(NULL));
  for (i = 0; i < n; i++)
  {
    score[i] = rand() % 11;
  }
}

/* deviation_score */
double calc_deviation_score(int n, int* score, int ten)
{
  int i;
  double hensa;
  double hensa2_array[N];
  double hensati;

  double hensa2_ave;
  double hensa2_sum = 0;


  for (i = 0; i < n; i++)
  {
    hensa = score[i] - calc_ave(N, score);
    hensa2_array[i] = hensa * hensa;
  }


  for(i = 0; i <= n-1 ; i++){
    hensa2_sum = hensa2_sum + hensa2_array[i];
  }
  hensa2_ave = (double)hensa2_sum / n;


  hensati = (( ten - calc_ave(N, score) ) / sqrt(hensa2_ave)) * 10 + 50;

  return hensati;
}



/* print_array */
void print_array(int n, int* a)
{
  int i;
  int score[N];
  for (i = 0; i < n; i++){
    printf("%d    ", a[i]);
    printf("%f", calc_deviation_score(N, score, score[i]));
    printf("\n");
  }

}


/* max */
int find_max_in_array(int n, int* score)
{
  int id = 0;
  int max = score[0];
  int i;
  for (i = 1; i < n ; i++) {
    if (score[i] > max  ) {
      id =i ;
      max = score[id];
    }
  }
  return id;
}



/* average */
double calc_ave(int n, int* score)
{
  int i;
  int sum_score = 0;
  double ave_score;

  for(i = 0; i <= n-1 ; i++){
    sum_score = sum_score + score[i];
  }
  ave_score = (double)sum_score / n;
  return ave_score;
}


/* swap */
void swap(int *a, int *b)
{
  int c;
  c = *b;
  *b = *a;
  *a = c;
}


/* sort */
void bubble_sort(int n, int *score)
{
  int i, j;
  for (i = n-1; i >  0; i-- ){
    for (j = 0; j < i; j++ ){
      if (score[j] > score[j+1])
        swap(&score[j] , &score[j+1]);
    }
  }
}

試したこと

点数の配列をランダムではなく自分で指定する方法のプログラムを作ったところ正しい偏差値が表示されたので、偏差値を求める関数calc_deviation_score() とその中で呼び出す関数 calc_ave() の式自体には問題はないかと思われます。

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define N 5

double calc_deviation_score(int n, int* score, int ten);
double calc_ave(int n, int* score);


int main(void)
{
  int i;
  int score[5];

  score[0] = 1;
  score[1] = 4;
  score[2] = 5;
  score[3] = 8;
  score[4] = 8;

  for (i = 0; i < 5; i++){
    printf("%d   ", score[i]);
    printf("%f", calc_deviation_score(N, score, score[i]));
    printf("\n");
  }

  return 0;
}



/* deviation_score */
double calc_deviation_score(int n, int* score, int ten)
{
  int i;
  double hensa;
  double hensa2_array[N];
  double hensati;

  double hensa2_ave;
  double hensa2_sum = 0;


  for (i = 0; i < n; i++)
  {
    hensa = score[i] - calc_ave(N, score);
    hensa2_array[i] = hensa * hensa;
  }


  for(i = 0; i <= n-1 ; i++){
    hensa2_sum = hensa2_sum + hensa2_array[i];
  }
  hensa2_ave = (double)hensa2_sum / n;


  hensati = (( ten - calc_ave(N, score) ) / sqrt(hensa2_ave)) * 10 + 50;

  return hensati;
}


/* average */
double calc_ave(int n, int* score)
{
  int i;
  int sum_score = 0;
  double ave_score;

  for(i = 0; i <= n-1 ; i++){
    sum_score = sum_score + score[i];
  }
  ave_score = (double)sum_score / n;
  return ave_score;
}

実行結果は以下の通りです。
(点数 標準偏差 の順に表示しています。)

1   34.079941
4   45.451412
5   49.241902
8   60.613373
8   60.613373

同様にscore[1]=8 score[3]=4 などscoreの順番を入れ替えて宣言してからバブルソートの関数をかませても同様の結果が得られました。

点数をランダムで作るアルゴリズムが原因でおかしくなってしまったのでしょうか。

補足情報

はじめは[点数][偏差値]の二次元配列を作ることを考えたのですが、まだ授業でポインタについて詳しくやっておらずほかの関数で呼び出す方法が難しそうだったため上のようなやり方で行いました。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+1

print_array()関数が間違っています。
未初期化のローカル変数score[i]がprintf()関数に渡されてますよ。
※標準偏差の結果が正しいかどうかは分かりません。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/12/19 00:28

    ご回答ありがとうございます。
    頂いたコメントをもとに print_array()関数を直してみて実行したところ、それらしい値が得られました。下の記述で初期化できているのでしょうか?? もし直したほうが良い記述があれば今後の勉強のためアドバイスを頂けたら幸いです。

    /* print_array */
    void print_array(int n, int* a)
    {
    int i;
    int ten = 0;

    for (i = 0; i < n; i++){
    printf("%d ", a[i]);
    ten = a[i];
    printf("%f", calc_deviation_score(N, a, ten));
    printf("\n");
    }

    }

    キャンセル

  • 2018/12/19 18:52

    修正後のコードで問題ないと思います。
    あとは、間違いではないですがcalc_deviation_score()関数の中で何回もcalc_ave()を呼び出していますよね。これは無駄だと思います。平均値の計算は1回やれば十分ですよね。

    キャンセル

  • 2018/12/20 01:14

    ご指摘ありがとうございます!プログラムを改良して無事完成させることができました。

    最近c言語を始めたばかりでポインタや初期化などは以前扱っていた言語(python)ではあまり気にしていなかった部分だったので、自分では間違いに気づけなかったため本当に助かりました。ありがとうございました!

    キャンセル

0

回答ではありませんが、、、

偏差値ってなんでしたっけ?
確か、点数の分布が正規分布になる場合に意味を持つものでなかったでしょうか?
そうすると、0..10 の乱数を点数として場合、標準偏差が定義できるのでしょうか?
点数を事前に用意した場合、偏った分布になるので、それらしい結果が得られると思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/12/19 00:39

    コメントありがとうございます。
    偏差値は平均点を50としたときに自分の点がどのくらいの値になるかで定義の式があるみたいです。
    調べてでてきた式をそのまま使いましたがおそらく正規分布じゃなくても値自体は出せるようです。
    ただ、今回は乱数を用いて点数を生成したため、値を出しただけでおっしゃる通り出力した偏差値自体から何か推測できるなどの統計学的な意味は持たないと思います。

    キャンセル

  • 2018/12/19 19:14

    正規分布する乱数食わせてみればいいよ。単純にはN個の一様乱数の平均を取ればNを大きくすると正規分布する。

    キャンセル

  • 2018/12/19 23:23

    確かに、正規分布する乱数を食わしてみれば、良いですね。

    なお、計算式のみは、ざっと見た限り、そんなもんて感じでした。
    平均を取って、それぞれの点数と平均の差の二乗。
    (ただ、毎回、平均の計算してるのは無駄っぽいですが)

    そういう意味では、計算は合っている? (他にも問題はあるとの事ですが)

    キャンセル

  • 2018/12/20 01:28

    正規分布する乱数を生成する方法があるのですね。(実を言うと今回作成した乱数発生の関数は授業時に与えられたサンプルの数値を少しいじっただけで仕組みはあまり理解できていないのが現状です)

    平均値の関数の呼び出しについてご指摘ありがとうございます。今までは動けばいいかなと思って気にしたことがあまりなかったのですがやはり今後長いプログラムを書くようになることを考えると同じ記述を何度も書くのはよくないですよね、、、

    まだまだ勉強不足だなと実感いたしました。 正規分布する乱数についても調べてみようと思います。ありがとうございます。

    キャンセル

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

  • ただいまの回答率 88.81%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る