今回は,これまでの演習の解答を解説します。内容を完璧に理解しましょう.わからないところがあったら,聞いて下さい。
(1)【関数とポインタ】30件の数字データ30data.txtを読み込み,値を大きい順に並び替え,別のファイル(30data_sorted.txt)に出力せよ.
#include <stdio.h>
void read(int data[],int n)
{
int i;
FILE *fp;
fp = fopen("30data.txt","r");
if(fp == NULL){
printf("ファイルを作れませんでした");
return;
}
for(i=0; i<n; i++){
fscanf(fp,"%d",&(data[i]));
}
fclose(fp);
}
void sort(int a[],int n)
{
int b,i,j;
for(i=0; i<n-1; i++){
for(j=i+1; j<n; j++){
if(a[i]<a[j]){
b = a[i];
a[i] = a[j];
a[j] = b;
}
}
}
}
void write(int data[],int n)
{
int i;
FILE *fp;
fp = fopen("30data_sorted.txt", "w");
if(fp == NULL){
printf("ファイルを作れませんでした");
return;
}
for(i=0; i<n; i++){
fprintf(fp, "%d \n",data[i]);
}
fclose(fp);
}
void main()
{
int data[30];
read(data,30);
sort(data,30);
write(data,30);
}
(2)【構造体】5件の名前,出身地,生年のデータファイルがある.
このファイルは,名前 出身地 年齢 西暦 の順にデータが並んでいる.
(a) 構造体を用いて,このファイルを読み込んで画面に出力しなさい.
(b) 2012年と生年との差を計算し,データの3列目に代入しなさい.(年の初期値は0となっている.)
(c) 年が上書きされたデータを[result.csv]というファイルに書き出しなさい.
#include <stdio.h>
struct data
{
char name[50];
char birthplace[50];
int age;
int ad;
};
void main()
{
int i, n;
struct data list[5];
FILE *fp;
fp = fopen("data.txt","r");
if(fp == NULL){
printf("ファイルがありませんでした");
return 0;
}
for(i=0; i<5; i++){
fscanf(fp,"%s %s %d %d",list[i].name,list[i].birthplace,&(list[i].age),&(list[i].ad));
printf("%s %s %d %d\n",list[i].name,list[i].birthplace,list[i].age,list[i].ad);
list[i].age = 2012-list[i].ad;
}
fclose(fp);
fp = fopen("result.csv","w");
if(fp == NULL){
printf("ファイルを作れませんでした");
}
for(i=0; i<n; i++){
fprintf(fp,"%s,%s,%d,%d\n",list[i].name,list[i].birthplace,list[i].age,list[i].ad);
}
fclose(fp);
}
(3)【グラフィックス】初速v0=50(m/s),角度θ=45°で放たれた球が,地面に衝突し跳ね返り続ける球の軌跡をグラフィックスを用いて描きなさい.
ただし,はね返り係数e=0.8,重力加速度g=9.81(m/s2)とし,空気抵抗は無視する.また,斜方投射の式は以下を参照すること
水平方向の距離 x=(v0×cosθ)×t ,鉛直方向の距離 y=(eJ×v0×sinθ)×t-g×t2/2 (t : 時間 ,J : 衝突回数)
#include <stdio.h>
#include <math.h> /* 三角関数を使うため */
#include "mogra.f" /* グラフィックスライブラリ */
void main()
{
int i;
float t;
int j = 0; /* 衝突回数 */
float te = 0; /* 衝突した時刻 */
float x, y;
float v0 = 50.0; /* 初速 */
float th = 3.141/4; /* 投射角(rad) */
float g = 9.81; /* 重力加速度 */
float e = 0.8; /* 反発係数 */
g_int(640, 480);
for(t=0; t<40; t+=0.1){
x = v0 * cos(th) * t;
y = pow(e,j) * v0 * sin(th) * (t-te) - g * (t-te) * (t-te) / 2;
if(y < 0){ /* 衝突!! */
y = -y; /* 向きを変える */
j++; /* 衝突回数を数える */
te = t; /* 衝突した時刻を覚えておく */
}
printf("%f %f\n", x, y);
circle(x/2, 480-y*4, 10, 0); /* x, y に倍率をかけて、上下反転して見た目調整 */
for(i=0; i<10000000; i++){}; /* 無駄に計算させて、時間をかけて、リアルに描画する */
}
gend();
}
初速,投射角等を変えて,シミュレーションしてみよう。
(1)度数分布(ヒストグラム)とは,統計において標本として得られたある変量の値のリストである.一般に量の大小の順で並べ、各数値が現われた個数を表示する表(度数分布表)で示される.テストの点数のような離散型変量の場合,度数分布表(ヒストグラム)に表すことで,データ全体の分布状況が視覚的に明らかにすることができる.エクセルを用いて度数分布(ヒストグラム)を表示させようと思うと,なかなかすぐにはできない.そこで,パソコンに度数分布を計算してもらうプログラムを作成してみましょう.
#include <stdio.h>
#include <math.h> /* sqrt関数を使うため */
struct testdata{
char name[20]; /* 名前 */
int score; /* 点数 */
float deviation_value; /* 偏差値 */
int ranking; /* 順位 */
};
void main()
{
FILE *fp;
struct testdata a[50];
int i, j, sum=0, sum2=0, rank, n=1;
float ave, dev;
int hist[11]={0,0,0,0,0,0,0,0,0,0,0};
/* (1)ファイルから読み込み画面に表示する */
fp = fopen("50data.txt","r");
for(i=0; i<50; i++){
fscanf(fp, "%s %d", &(a[i].name), &(a[i].score));
printf("%s %d\n", a[i].name, a[i].score);
}
fclose(fp);
/* (2)平均点標準偏差の算出 */
/* 平均点を求める */
for(i=0; i<50; i++){
sum+=a[i].score;
}
ave = (float)sum/50;
/* 平均点を用いて分散を求め,標準偏差を求める */
for(i=0; i<50; i++){
sum2+=(a[i].score-ave)*(a[i].score-ave);
}
dev = sqrt((float)sum2/50);
printf("平均点:%.1f,標準偏差:%.1f\n", ave, dev);
/* 偏差値の算出と代入 */
for(i=0; i<50; i++){
a[i].deviation_value = 10*(a[i].score-ave)/dev+50;
}
/* (3)順位をつける 100点の人が1位、そこから下げていく */
for(i=100;i>=0;i--){
rank = n; /* ここまでの順位は、順位のすでに決まった人の人数 */
for(j=0; j<50; j++){
if(a[j].score == i){
a[j].ranking = rank;
n++; /* 順位のついた人の人数を1増やす */
}
}
}
for(i=0; i<50; i++){
printf("%s %d %.1f %d\n", a[i].name, a[i].score, a[i].deviation_value, a[i].ranking);
}
/* (4)度数分布を計算する */
for(i=0; i<50; i++){
hist[a[i].score/10]++;
}
/* ファイルに保存する */
fp = fopen("histogram.csv", "w");
for(i=0; i<11; i++){
fprintf(fp, "%d,%d \n", i, hist[i]);
}
fclose(fp);
/* アスキーアートで表示する */
for(i=0; i<11; i++){
printf("%3d- %2d ", i*10, hist[i]);
/* ヒストグラム */
for(j=0; j<hist[i]; j++){
printf("*");
}
printf("\n");
}
}
(2)ある物体の質量をm,ばねのばね定数をk,減衰器の減衰係数をbとおくと,減衰振動の運動方程式は,
mx"=-kx-bx'
となり,
x" = -(k/m)x - (b/m)x'
となります.ここで,k/m = w02,b/m = 2r とすると,
x" = -w02x - 2r x'
と変形できる。この微分方程式の解は,3つ(4つ)の場合に分かれる。
摩擦の無い場合(r=0)
x = 2 |A| cos(w0t)
減衰振動(r < w0)
x = e-rt 2 |A| cos(w1t)
w12 = w02 - r2
臨界減衰振動(r = w0)
x = 2 |A| (1 + w0t)e-wot
過減衰(r > w0)
摩擦の無い場合と,減衰振動(r=0.1w, 0.3w 0.5w 0.8w)の場合を同じグラフに重ね合わせて表示しなさい。
#include <stdio.h>
#include <math.h>
#include "mogra.f"
void main()
{
int i;
float a=100,x,m=10,k=0.1,t,r[5],w0,w1,e;
w0=sqrt(k/m);
g_int(640,480);
r[0]=0;
r[1]=0.1*w0;
r[2]=0.3*w0;
r[3]=0.5*w0;
r[4]=0.8*w0;
for(t=0;t<500;t=t+0.01){
for(i=0;i<5;i++){
if(r[i]==0){
x=2*a*cos(w0*t);
}
else if(r[i]<w0){
w1=sqrt(w0*w0-r[i]*r[i]);
e=exp((-1)*r[i]*t);
x=e*2*a*cos(w1*t);
}
else if(r[i]==w0){
e=exp((-1)*w0*t);
x=2*a*(1+w0*t)*e;
}
pset(t,240-x,i+9);
}
}
gend();
}