C言語で最小値,平均値,最大値,合計値,標準偏差,中央値の計算方法を教えて!
こういった悩みにお答えします.
本記事の信頼性
- リアルタイムシステムの研究歴12年.
- 東大教員の時に,英語でOS(Linuxカーネル)の授業.
- 2012年9月~2013年8月にアメリカのノースカロライナ大学チャペルヒル校(UNC)コンピュータサイエンス学部で客員研究員として勤務.C言語でリアルタイムLinuxの研究開発.
- プログラミング歴15年以上,習得している言語: C/C++,Python,Solidity/Vyper,Java,Ruby,Go,Rust,D,HTML/CSS/JS/PHP,MATLAB,Verse(UEFN), Assembler (x64,aarch64).
- 東大教員の時に,C++言語で開発した「LLVMコンパイラの拡張」,C言語で開発した独自のリアルタイムOS「Mcube Kernel」をGitHubにオープンソースとして公開.
- 2020年1月~現在はアメリカのノースカロライナ州チャペルヒルにあるGuarantee Happiness LLCのCTOとしてECサイト開発やWeb/SNSマーケティングの業務.2022年6月~現在はアメリカのノースカロライナ州チャペルヒルにあるJapanese Tar Heel, Inc.のCEO兼CTO.
- 最近は自然言語処理AIとイーサリアムに関する有益な情報発信に従事.
- (AI全般を含む)自然言語処理AIの論文の日本語訳や,AIチャットボット(ChatGPT,Auto-GPT,Gemini(旧Bard)など)の記事を50本以上執筆.アメリカのサンフランシスコ(広義のシリコンバレー)の会社でプロンプトエンジニア・マネージャー・Quality Assurance(QA)の業務委託の経験あり.
- (スマートコントラクトのプログラミングを含む)イーサリアムや仮想通貨全般の記事を200本以上執筆.イギリスのロンドンの会社で仮想通貨の英語の記事を日本語に翻訳する業務委託の経験あり.
こういった私から学べます.
C言語を独学で習得することは難しいです.
私にC言語の無料相談をしたいあなたは,公式LINE「ChishiroのC言語」の友だち追加をお願い致します.
私のキャパシティもあり,一定数に達したら終了しますので,今すぐ追加しましょう!
独学が難しいあなたは,元東大教員がおすすめするC言語を学べるオンラインプログラミングスクール5社で自分に合うスクールを見つけましょう.後悔はさせません!
目次
最小値,平均値,最大値,合計値,標準偏差の計算
C言語で最小値,平均値,最大値,合計値,標準偏差を計算する標準ライブラリ関数はないので,自作します.
\(n\)個のデータ\(x_1, x_2, …, x_n\)における最小値(\(x_{\min}\)),平均値(\(x_{\rm avg}\)),最大値(\(x_{\max}\)),合計値(シグマ\(\Sigma_{i=1}^n x_i\))の計算は下式になります.
\begin{eqnarray*}
x_{\min} &=& \min(x_1, x_2, ..., x_n) \\
x_{\rm avg} &=& \frac{\Sigma_{i=1}^n x_i}{n} \\
x_{\max} &=& \max(x_1, x_2, ..., x_n) \\
\Sigma_{i=1}^n x_i &=& x_1 + x_2 + ... + x_n
\end{eqnarray*}
標準偏差\(s\)は,\(n\)個のデータ\(x_1, x_2, …, x_n\)とその平均\(\overline{x}\)を用いて下式になります.
$$s = \sqrt{\frac{1}{n}\sum_{i = 1}^n {(x_i - \overline{x})^2}}$$
また,分散\(s^2\)は標準偏差の平方根の中身になります.
$$s^2 = \frac{1}{n}\sum_{i = 1}^n {(x_i - \overline{x})^2}$$
最小値,平均値,最大値,合計値,標準偏差を計算するコードは以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <math.h> int array[] = {10, -100, 33, 22, 567, -44, 77}; #define NR_ELEMENTS (sizeof(array) / sizeof(array[0])) int main(void) { int min, max, sum; double avg, stddev, var; int i; min = max = sum = array[0]; for (i = 1; i < NR_ELEMENTS; i++) { sum += array[i]; if (min > array[i]) { min = array[i]; } if (max < array[i]) { max = array[i]; } } avg = (double) sum / NR_ELEMENTS; printf("min = %d, avg = %lf, max = %d\n", min, avg, max); printf("sum = %d\n", sum); var = 0.0; for (i = 0; i < NR_ELEMENTS; i++) { var += (array[i] - avg) * (array[i] - avg); } var /= NR_ELEMENTS; stddev = sqrt(var); printf("var = %lf, stddev = %lf\n", var, stddev); return 0; } |
実行結果は以下になります.
1 2 3 4 5 |
$ gcc min_avg_max_sum_stddev.c -lm $ a.out min = -100, avg = 80.714286, max = 567 sum = 565 var = 42203.346939, stddev = 205.434532 |
平方根を計算するsqrt関数を知りたいあなたはこちらからどうぞ.
中央値の計算
中央値とは,データを大きい順(または小さい順)に並べた時の中央にある値のことです.
データ数が偶数の場合は,中央の2つの値の平均値を中央値とします.
中央値の計算方法として以下の2種類の方法を紹介していきます.
データをソートした後に中央値の取得
一番思いつきやすい方法は,データをソートした後に中央値の取得する方法です.
また,qsort関数でデータをクイックソートした後に中央値を取得するコードは以下になります.
qsort関数の使い方を知りたいあなたはこちらからどうぞ.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #define NR_ELEMENTS(a) (sizeof((a)) / sizeof((a)[0])) int arraycmp(const void *p1, const void *p2) { return *(const int *) p1 > *(const int *) p2; } bool is_odd_number(int n) { return n & 0x1; } double get_median(int n, int a[]) { int k = n / 2; qsort(a, n, sizeof(int), arraycmp); if (is_odd_number(n)) { return a[k]; } else { return (double)(a[k - 1] + a[k]) / 2; } } int main(void) { int array[] = {11, -100, 33, 22, 567, -44, 77}; int array2[] = {11, -100, 33, 22, 567, -44, 77, 0}; printf("get_median(%lu, array) = %lf\n", NR_ELEMENTS(array), get_median(NR_ELEMENTS(array), array)); printf("get_median(%lu, array2) = %lf\n", NR_ELEMENTS(array2), get_median(NR_ELEMENTS(array2), array2)); return 0; } |
実行結果は以下になります.
データ数が奇数と偶数の両方の場合で,中央値が正しく計算できていることがわかります.
1 2 3 4 |
$ gcc med.c $ a.out get_median(7, array) = 22.000000 get_median(8, array2) = 16.500000 |
中央値(k番目に大きい値・小さい値)を探すパーティションベースの汎用選択アルゴリズム
中央値を探すためにデータが格納されている配列をソートすると,\(\mathcal{O}(n \log n)\)の平均計算量になってしまいます.
そこで,パーティションベースの汎用選択アルゴリズムを利用することで,中央値を\(\mathcal{O}(n)\)の平均計算量で探すことができます.
※一般的には,パーティションベースの汎用選択アルゴリズムは,k番目に大きい値・小さい値を探すアルゴリズムです.
パーティションベースの汎用選択アルゴリズムで中央値を探すコードは以下になります.
※C言語の配列は0オリジンで始まることに注意して下さい.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <stdbool.h> #define NR_ELEMENTS(a) (sizeof((a)) / sizeof((a)[0])) void swap(int *x, int *y) { int tmp; tmp = *x; *x = *y; *y = tmp; } int partition(int left, int right, int pivot_index, int a[]) { int pivot_value, store_index; int i; pivot_value = a[pivot_index]; swap(&a[pivot_index], &a[right]); store_index = left; for (i = left; i <= right - 1; i++) { if (a[i] <= pivot_value) { swap(&a[store_index], &a[i]); store_index++; } } swap(&a[right], &a[store_index]); return store_index; } int selection(int left, int right, int k, int a[]) { int pivot_new_index; while (true) { pivot_new_index = partition(left, right, k, a); if (k == pivot_new_index) { return a[k]; } else if (k < pivot_new_index) { right = pivot_new_index - 1; } else { left = pivot_new_index + 1; } } } bool is_odd_number(int n) { return n & 0x1; } double get_median(int n, int a[]) { int val, val2; int k = n / 2; val = selection(0, n - 1, k, a); if (is_odd_number(n)) { return val; } else { val2 = selection(0, n - 1, k - 1, a); return (double)(val + val2) / 2; } } int main(void) { int array[] = {11, -100, 33, 22, 567, -44, 77}; int array2[] = {11, -100, 33, 22, 567, -44, 77, 0}; printf("get_median(%lu, array) = %lf\n", NR_ELEMENTS(array), get_median(NR_ELEMENTS(array), array)); printf("get_median(%lu, array2) = %lf\n", NR_ELEMENTS(array2), get_median(NR_ELEMENTS(array2), array2)); return 0; } |
実行結果は以下になります.同様です.
1 2 3 4 |
$ gcc med2.c $ a.out get_median(7, array) = 22.000000 get_median(8, array2) = 16.500000 |
partition関数で利用しているswap関数を深掘りしたいあなたはこちらからどうぞ.
まとめ
C言語で最小値,平均値,最大値,合計値,標準偏差,中央値の計算方法を紹介しました.
最小値,平均値,最大値,合計値はシンプルな計算で求めました.
標準偏差で平方根を計算する場合は,標準ライブラリのsqrt関数と自作したmysqrt関数のコードを紹介しました.
また,中央値はパーティションベースの汎用選択アルゴリズムで探しました.
よく使う方法ですので,きちんと理解しましょう!
C言語を独学で習得することは難しいです.
私にC言語の無料相談をしたいあなたは,公式LINE「ChishiroのC言語」の友だち追加をお願い致します.
私のキャパシティもあり,一定数に達したら終了しますので,今すぐ追加しましょう!
独学が難しいあなたは,元東大教員がおすすめするC言語を学べるオンラインプログラミングスクール5社で自分に合うスクールを見つけましょう.後悔はさせません!