東京工芸大学 工学部  電子機械学科 2年 前期 

基礎プログラミング 第12回
 2017.7.27藤木 文彦
http://fujiki.tv/t-kougei/kisoprog/
fujiki.kougei@gmail.com  




 
実行画面の印刷


実行画面をプリンタに印刷して提出してもらいます。

方法は、授業中に教室で実演しますので見てください。

 プログラムを実行し画面が表示されている状態で、「Word」を起動します。

 まず、自分の名前と 学生番号を記入しなさい。


次に、Wordの画面で、
   「挿入」 ー> 「スクリーンショット」 を選ぶと、現在ウインドウに表示されている画面が並んで表示されます。

 その中で、実行中の画面を選ぶと、編集画面に、画面のイメージがコピーされます。


 次のように、先頭に 氏名と学生番号、問題番号を記述し、印刷しなさい。(ファイルは保存してもしなくても良い。)


提出するプリントのレイアウト例  (番号、氏名は、少し大きめの字にすると良い)

第12回 問題 1

氏名   藤木 工芸 
番号   e00000000











画像の大きさを調整して、1ページに収まるようにしたら、その画像を、印刷します。(白黒で良い。授業時間中の課題提出用のプリントは、年間100枚の枚数制限の対象外です。授業時間をはずれると、年間印刷枚数の対象となります。)

  1.キャラクタベースでのグラフ表示 
画面上に縦横に”*”を描く


2つの数(縦、横)を入力し、その大きさの四角を "*" 印で書く。

  (例題1) 

Project1201

 // Project1201.cpp : コンソール アプリケーションのエントリ ポイントを定義します。
//

#include "stdafx.h"
#include "iostream"
#include "fstream"
using namespace std;

#define MAX 10

int _tmain(int argc, _TCHAR* argv[])
{
    int c=0,x,y;
    while( ++c <= 10 ){
        printf("横 x, 縦 y を入力してください。( x:0-%d y:0-%d)",MAX,MAX);
// scanf("%d %d",&x,&y);
        cin >> x >> y;
        if( x>=0 && x<=MAX && y>=0 && y<=MAX ){
            break;
        }else{
            printf("範囲を超えています。 \n");
        }
    }
    cout <<"-----------------------\n";
    printf("x= %d y= %d\n",x,y );
    for ( int iy=0; iy< y; iy++){
        for( int ix=0; ix<x; ix++){
            cout <<"*";
        }
        cout << "\n";
    }
    getchar();
    getchar();
return 0;
}




 【演習問題1】 


 上記プログラムの一部を書き換えて、

縦横20個ずつの "#" を表示させるようにしなさい。

 以上の変更点を加えて動かしたら、
  実行した 画面
  プログラムの主要部分
 を、コピーしてメールに貼り付け、  "Project1201" として送りなさい。

★実行画面をキャプチャーし、印刷して、教卓に提出しなさい。


  2.sin cos の値を表示する


sin cos の値を求めて表示する

表示する桁数を指定して、そろえるために、 setw( ) という関数を使います。そのために、 #include "iomanip" を加えます。
また、数学関数(sin, cos や、log など)を表示するために、 #include "math.h" を加えます。

  (例題2) 

Project1202

 // Project1202.cpp : コンソール アプリケーションのエントリ ポイントを定義します。
//

#include "stdafx.h"

#include "iostream"
#include "fstream"
#include "iomanip"
#include "math.h"

#define PI 3.14159265

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    float a,asin, acos;
    for ( int i = 0; i<=180; i+=30){
        a=PI*i/180;
        asin = sin(a);
        acos = cos(a);
        cout <<"角度" << setw(5) <<i
            <<" ラジアン" << setw(10) << a
            <<" Sin = " << setw(10) << asin
            <<" Cos = " << setw(10) << acos << "\n";
    }
    getchar();
    getchar();
    return 0;
}
//http://www.math.meiji.ac.jp/~mk/labo/studying-C/Programing-in-C/node244.html

実行例

角度    0 ラジアン           0 Sin =           0 Cos =           1
角度  30 ラジアン 0.523599 Sin =         0.5 Cos = 0.866025
角度  60 ラジアン    1.0472 Sin = 0.866025 Cos =         0.5
角度  90 ラジアン    1.5708 Sin =           1 Cos = -4.37114e-008
角度 120 ラジアン   2.0944 Sin = 0.866025 Cos =        -0.5
角度 150 ラジアン  2.61799 Sin =        0.5 Cos = -0.866025
角度 180 ラジアン  3.14159 Sin = -8.74228e-008 Cos =      -1

上の表示では、欄が揃っていないのですが、画面コピーを掲げます。
(ほとんど)揃っています。


なお、一部に  e-008 を含むおかしな表示部分がありますが、その理由は次に説明しますので、ここでは、それによる表示の乱れはそのまま出力してください。

 【演習問題2】 


 上記プログラムの一部を書き換えて、

 sin, cos を、 0度から、360度まで、 15度刻みで表示するようにしなさい。

 以上の変更点を加えて動かしたら、
  実行した 画面
  プログラムの主要部分
 を、コピーしてメールに貼り付け、  "Project1202" として送りなさい。
★実行画面をキャプチャーし、印刷して、教卓に提出しなさい。

  3.小さな値を0とみなす方法


 上の実行例で、欄が揃わなかった部分をみると、どうも、非常に小さい数の部分が指数形式
 x.xxxxxxx e-008
 のように表されているためであることが分かります。
 ここは、数値に近似値を用いたため、本来 0 となるところが、正確に0とならずに、小さな数となってしまったためであると考えられます。

指数数形式表示:
1.23456e-008  とは、 1,23456 × 10 の -8乗という意味です。


 そこで、非常に小さい値は、0と見なすようにする工夫をしてみます。

marume( ) という関数を作って、絶対値( abs( ) ) が、ある一定値以下のものを 0 とします。

  (例題3) 

Project1203

 // Project1203.cpp : コンソール アプリケーションのエントリ ポイントを定義します。
//

#include "stdafx.h"

#include "iostream"
#include "fstream"
#include "iomanip"
#include "math.h"
//#include "cmath"

#define PI 3.14159265
#define STEP 10
using namespace std;


float marume( float x ){
    if( abs(x) < 0.00001 ){
        x=0;
    }
    return x;
}

int _tmain(int argc, _TCHAR* argv[])
{
    float a,asin, acos;
    for ( int i = 0; i<=180; i+=STEP){
        a=PI*i/180;
        asin = sin(a);
        asin = marume(asin);
        acos = cos(a);
        acos = marume(acos);

        cout <<"角度" << setw(5) <<i
            <<" ラジアン" << setw(10) << a
            <<" Sin = " << setw(10) << setprecision(4) << asin
            <<" Cos = " << setw(10) << acos << "\n";
    }

    getchar();
    getchar();
    return 0;
}

// cout 書式
// http://www.math.meiji.ac.jp/~mk/labo/studying-C/Programing-in-C/node244.html
// 桁揃え
// http://d.hatena.ne.jp/hidemon/20080715/1216111956


 


 【演習問題3】 


 上記プログラムでは、出力される数値の小数点の位置がそろっていないために、表示が見にくくなっています。

 数値表示を左側にそろえるためには、 << setw(10) << left   のような指定を使います。

 なお、表示の途中で、   

<< setprecision(4)

という制御出力が行われています。これが、どんな働きをするものか、数値を、 4から、2とか3とかに変更して実験してみた上で、その働きを考えて、メールの最初に書きなさい。

まずはじめに、上に書かれた問題に対する答えを、数行で書いた後に、

  実行した 画面
  プログラムの主要部分
 を、コピーしてメールに貼り付け、  "Project1203" として送りなさい。
★実行画面をキャプチャーし、印刷して、教卓に提出しなさい。

  4.sin 曲線の簡易グラフィック表示


 グラフィック画面が使えないようなコンピュータで、擬似的にグラフを表示する方法を示します。

 詳細説明は省略しますので、以下のプログラムを入力し、実行してみてください。

  (例題4) 

Project1204

// Project1204.cpp : コンソール アプリケーションのエントリ ポイントを定義します。
//

#include "stdafx.h"

#include "iostream"
#include "fstream"
#include "iomanip"
#include "math.h"
//#include "cmath"

#define PI 3.14159265
#define STEP 15
#define MAX 360
#define OFFSET 20
using namespace std;


float marume( float x ){
    if( abs(x) < 0.00001 ){
        x=0;
    }
    return x;
}

int _tmain(int argc, _TCHAR* argv[])
{
    float a,asin;
    int isin;

    for ( int i = 0; i<=MAX; i+=STEP){
        a=PI/180 *i;
        asin = sin(a);
        asin = marume(asin);
        isin = (int)( asin * OFFSET + OFFSET );

        cout <<"角度" << setw(5) <<i;
        for( int j=0; j<isin; j++){
            if( j == OFFSET ){
                cout << "|";
            }else{
                cout << ".";
            }
        }
        cout << "*"
        << "\n";
    }

    getchar();
    getchar();
    return 0;
}



実行例

 
角度   0....................*
角度  15....................|....*
角度  30....................|.........*
角度  45....................|.............*
角度  60....................|................*
角度  75....................|..................*
角度  90....................|...................*
角度 105....................|..................*
角度 120....................|................*
角度 135....................|.............*
角度 150....................|.........*
角度 165....................|....*
角度 180....................*
角度 195..............*
角度 210..........*
角度 225.....*
角度 240..*
角度 255*
角度 270*
角度 285*
角度 300..*
角度 315.....*
角度 330.........*
角度 345..............*
角度 360....................*

 【演習問題4】 


 上記のプログラムの動作が確認できたら、同様に、 cos カーブを、0度から360度まで表示させて見なさい。

  実行した 画面
  プログラムの主要部分
 を、コピーしてメールに貼り付け、  "Project1204" として送りなさい。

★実行画面をキャプチャーし、印刷して、教卓に提出しなさい。

  5.対数やべき乗の計算法


 次に、 sin、cos の他に、 べき乗や、対数などの数学関数を使う方法を紹介しておきます。

  (例題5) 

Project1205

 // Project1205.cpp : コンソール アプリケーションのエントリ ポイントを定義します。
//

#include "stdafx.h"

#include "iostream"
#include "fstream"
#include "iomanip"
#include "math.h"
//#include "cmath"

#define PI 3.14159265
#define STEP 10
using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{

    cout << "log 10 " << log(10.0) << "\n";
    cout << "2の5乗 "<< pow(2.0,5.0) << "\n";
    cout <<"2の平方根 " << sqrt(2.0) << "\n";
    getchar();
    getchar();
    return 0;
}

// 文字列、数学関数の使い方

//http://www9.plala.or.jp/sgwr-t/c/sec07.html

 


 【演習問題5】 


 上記プログラムを改良して、求める数値を、キーボードから入力できるようにしなさい。

 たとえば、次のようになるものとします。

 logを求める数値を入力してください。
 5
 log 5 = ******

 2の何乗かを求める数値を入力してください。
12.5
2の 12.5 乗 = ************

平方根を求める数値を入力してください。
7.3
7.3 の平方根 = ************


 注意してほしいのは、上記のプログラムを見ると分かるように、数学関数に与える数値は、整数型ではなく、浮動小数点型でなければならない点です。
 そのために、入力する数値は、float (または double )として宣言してから入力を受け付けるようにしないとなりません。


上記のようにプログラムを改良したら、

  実行した 画面
  プログラムの主要部分
 を、コピーしてメールに貼り付け、  "Project1205" として送りなさい。
★実行画面をキャプチャーし、印刷して、教卓に提出しなさい。


  6.グラフィック表示の縦横の変換

 前のグラフは、x軸が下向き、y軸が右向きになっています。

 この表示を普通のグラフで書くように、右向きをx 上向きをy とした形で表示したいですね。
 グラフィック機能を使わないので、上から順番に書くしかないとすると、このような出力は難しいですね。このようなときは、出力をいったん2次元配列に入れて、その後、配列の向きを変えて出力する、という方法をとります。

 これも、詳細は省略しますので、プログラムを入力して動作を確認してください。

  (例題6) 

Project1206

 // Project1206.cpp : コンソール アプリケーションのエントリ ポイントを定義します。
//

#include "stdafx.h"
#include "stdafx.h"

#include "iostream"
#include "fstream"
#include "iomanip"
#include "math.h"
//#include "cmath"

#define PI 3.14159265
#define STEP 15
#define MAX 360
#define OFFSET 20
using namespace std;


float marume( float x ){
    if( abs(x) < 0.00001 ){
        x=0;
    }
    return x;
}

int _tmain(int argc, _TCHAR* argv[])
{
    float a,asin;
    int isin;
    int x,y;
    int wx = 360 / STEP + 1;
    int wy = OFFSET * 2 + 1;
    char m[ 360 / STEP + 10 ][ OFFSET * 2 + 10 ];

    for ( int ix = 0; ix < wx; ix++ ){
        for ( int iy = 0; iy < wy; iy++ ){
            m[ix][iy] = ' ';
        }
    }

    for ( int i = 0; i <= MAX; i += STEP){
        a=PI/180 * i;
        x = i/STEP;
        asin = sin(a);
        asin = marume(asin);
        isin = (int)( asin * OFFSET + OFFSET );
        cout << isin;
        cout <<"角度" << setw(5) <<i;
        for( int j=0; j<isin; j++){
            y = j;
            if( j == OFFSET ){
                cout << '|';
                m[x][y]='-';
            }else{
                cout << '.';
                m[x][y] = '.';
            }
        }
        cout << '*'
            << '\n';
        m[x][y+1]='*';
    }

    for ( int y=wy-1; y>=0 ; y--){
        for( int x=0; x<wx; x++){
            cout << m[x][y] ;
        }
        cout << '\n';
    }

    getchar();
    getchar();
    return 0;
}



 【演習問題6】 

 上記のプログラムの動作が確認できたら、同様に、 cos カーブを、0度から360度まで表示させて見なさい。

  実行した 画面
  プログラムの主要部分
 を、コピーしてメールに貼り付け、  "Project1206" として送りなさい。

★実行画面をキャプチャーし、印刷して、教卓に提出しなさい。

  7.乱数の出し方


 プログラムの中には、乱数の必要になるものがあります。
 ここで、乱数を発生させるプログラムを示しておきます。

  (例題7) 

Project1207

 // Project1207.cpp : コンソール アプリケーションのエントリ ポイントを定義します。
//

#include "stdafx.h"

#include "iostream"
#include "fstream"
#include "iomanip"
#include "math.h"
#include "string.h"
#include "stdlib.h"

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    int d;
    srand( (unsigned int) time(NULL));
    for ( int i=0; i<10; i++){
        d=rand();
        cout << d <<" " << d%100 << '\n';
    }

    getchar();
    getchar();
    return 0;
}

 【演習問題7】 

 上記のプログラムの動作が確認できたら、
0.0 から 99 までの範囲の乱数(整数)を発生させるプログラムを作成してみなさい。

 出力は、横に10個ずつ、合計100個出力させなさい。


  実行した 画面
  プログラムの主要部分
 を、コピーしてメールに貼り付け、  "Project1207" として送りなさい。
★実行画面をキャプチャーし、印刷して、教卓に提出しなさい。



















 以下は覚え書きなので、演習しなくて良い。



 以下は、データファイルから配列状のデータを読み込む場合の方法を説明するために書いている途中のものですが、 Visual C++ 用に書き直さなければならないので、そのまま入力しても動きません。今後使用するときのための覚え書きとして掲げておきますが、演習としてやる必要はありません。

  8.大きさの変わる配列を読み込む方法

あらかじめデータの書かれたファイルを読み込むこともできます。
 ただし、配列を読み込むには、少し工夫が必要です。

 C言語では、実行されるプログラムの前に、使う変数の型や配列の大きさなどを宣言しておかなければなりません(最近のC言語ではその辺の柔軟度が増していますが、以前のC言語ではそのような決まりがありました。)
 配列の大きさは、データを読むまでわからないことが多くあります。

 ここでも、データファイルの中に配列の大きさを書き込んでおくような形式を考えます。
 しかし、この形式の場合、データを読み込む、という動作をしてからでは、配列の大きさを宣言することができません。
 (あらかじめ非常に大きな配列を用意しておく方法もありますが、どこまでの大きさのものを用意していいかわからないときはできません。)
 そこで、そこで、データを読み込んでから、配列を宣言する方法として、いったん配列の大きさを読み込んでから、「関数」にそれを渡し、関数の中で、配列を宣言して使う、という「裏ワザ」を使います。

  (例題8) 


 具体的には、次のようにします。

 実行する前に、次のような、データファイルを準備しておいてください。


最初の1行のデータが、横3行、縦5列のデータであることを示しています。

 arrayfile1.txt

3 5                      
11 12 13
21 22 23
31 32 33
41 42 43
51 52 53

Project1209

 このプログラムは、 C++ ではなく、旧 C 言語でかかれたものですので、修正しないと動きません。 

#include <stdio.h>

main(){

FILE *fp;
  int x,y;
    if((fp=fopen("arrayfile1.txt","r")) == NULL ){
      printf("err\n");
    }else{
      fscanf(fp,"%d %d",&x,&y);
    printf("%d %d\n",x,y);
    fclose(fp);
    func(x,y);
  }
}

func(int x, int y){
  FILE *fp2;
  int ax,ay;
  int ary[x][y];
    if((fp2=fopen("arrayfile1.txt","r")) == NULL ){
      printf("err\n");
    }else{
      fscanf(fp2,"%d %d",&x,&y);
      for( ay=0; ay<y; ay++){
        for( ax=0; ax<x; ax++ ){
          fscanf(fp2,"%d", &ary[ax][ay]);
          printf("%3d ",ary[ax][ay]*10);
        }
        printf("\n");
      }
    fclose(fp2);
  }
}

 【演習問題8】 





  9.方程式の解の近似値を求める(ニュートン法に類似の方法)

  (例題9) 

Project1209

 【演習問題9】