Download : sample-001.c
/*
* 2017/07/07 sample-001.c
*/
/*
* 型の違い
*
* 利用方法
* コンパイル
* cc -I ~/c/include -c sample-001.c
* リンク
* cc -o sample-001.exe sample-001.c
* 実行
* ./sample-001.exe
*/
#include <stdio.h>
#include "s_input.h"
#include "s_print.h"
/*
* main 関数
*/
int main ( void ) {
/*
* 型が違っても表示は同じ
*/
s_print_string ( "整数 : " );
s_print_int ( 9 );
s_print_newline();
s_print_string ( "文字 : " );
s_print_char ( '9' );
s_print_newline();
s_print_string ( "文字列 : " );
s_print_string ( "9" );
s_print_newline();
/*
* 整数の場合の +1
*/
s_print_string ( "整数の計算 : 9 + 1 = " );
s_print_int ( 9 + 1 );
s_print_newline();
/*
* 文字の場合の +1
*/
s_print_string ( "文字の計算 : '9' + 1 = " );
s_print_char ( '9' + 1 );
s_print_newline();
/*
* 文字列の場合の +1
*/
s_print_string ( "文字の計算 : \"9\" + 1 = " );
s_print_string ( "9" + 1 );
s_print_newline();
/*
* 型によって、計算結果が異る
*/
return 0;
}
$ ./sample-001.exe 整数 : 9 文字 : 9 文字列 : 9 整数の計算 : 9 + 1 = 10 文字の計算 : '9' + 1 = : 文字の計算 : "9" + 1 = $
Download : sample-002.c
/*
* 2017/07/07 sample-002.c
*/
/*
* 整数の四則計算式
*
* 利用方法
* コンパイル
* cc -I ~/c/include -c sample-002.c
* リンク
* cc -o sample-002.exe sample-002.c
* 実行
* ./sample-002.exe
*/
#include <stdio.h>
#include "s_input.h"
#include "s_print.h"
/*
* main 関数
*/
int main ( void ) {
/*
* 加法(足し算)
*/
s_print_string ( "12 + 5 = " );
s_print_int ( 12 + 5 ); /* 整数の 12 と 5 を加える */
s_print_newline();
/*
* 減法(引き算)
*/
s_print_string ( "12 - 5 = " );
s_print_int ( 12 - 5 ); /* 整数の 12 から 5 を引く */
s_print_newline();
/*
* 乗法(かけ算)
*/
s_print_string ( "12 * 5 = " );
s_print_int ( 12 * 5 ); /* 整数の 12 に 5 をかける */
s_print_newline();
/*
* 商法(割り算)
*/
s_print_string ( "12 / 5 = " );
s_print_int ( 12 / 5 ); /* 整数の 12 を 5 で割る */
s_print_newline();
/*
* 式の優先順位やかっこも利用可能
*/
s_print_string ( "1 + 2 * 3 = " );
s_print_int ( 1 + 2 * 3 ); /* かけ算が優先される */
s_print_newline();
s_print_string ( "(1 + 2) * 3 = " );
s_print_int ( (1 + 2) * 3 ); /* かっこの中の計算が優先される */
s_print_newline();
return 0;
}
$ ./sample-002.exe 12 + 5 = 17 12 - 5 = 7 12 * 5 = 60 12 / 5 = 2 1 + 2 * 3 = 7 (1 + 2) * 3 = 9 $
Download : sample-003.c
/*
* 2017/07/07 sample-003.c
*/
/*
* 文字列の演算式
*
* 利用方法
* コンパイル
* cc -I ~/c/include -c sample-003.c
* リンク
* cc -o sample-003.exe sample-003.c
* 実行
* ./sample-003.exe
*/
#include <stdio.h>
#include "s_input.h"
#include "s_print.h"
/*
* main 関数
*/
int main ( void ) {
/*
* 文字列への加法
*/
s_print_string ( "\"abc\" + 1 = " );
s_print_string ( "abc" + 1 ); /* 文字列が短くなる */
s_print_newline();
/*
* 先頭の文字の取出し
*/
s_print_string ( "*\"abc\" = " );
s_print_char ( *"abc" ); /* 先頭の文字が出て来る */
s_print_newline();
return 0;
}
$ ./sample-003.exe "abc" + 1 = bc *"abc" = a $
Download : sample-004.c
/*
* 2017/07/07 sample-004.c
*/
/*
* 関数呼出しを含む形の「式」
*
* 利用方法
* コンパイル
* cc -I ~/c/include -c sample-004.c
* リンク
* cc -o sample-004.exe sample-004.c
* 実行
* ./sample-004.exe
*/
#include <stdio.h>
#include "s_input.h"
#include "s_print.h"
/*
* main 関数
*/
int main ( void ) {
/*
* 加法(足し算)
*/
s_print_string ( "12 + 5 = " );
s_print_int ( 12 + 5 ); /* 整数の 12 と 5 を加える */
s_print_newline();
/*
* 減法(引き算)
*/
s_print_string ( "12 - 5 = " );
s_print_int ( 12 - 5 ); /* 整数の 12 から 5 を引く */
s_print_newline();
/*
* 乗法(かけ算)
*/
s_print_string ( "12 * 5 = " );
s_print_int ( 12 * 5 ); /* 整数の 12 に 5 をかける */
s_print_newline();
/*
* 商法(割り算)
*/
s_print_string ( "12 / 5 = " );
s_print_int ( 12 / 5 ); /* 整数の 12 を 5 で割る */
s_print_newline();
return 0;
}
$ ./sample-004.exe 12 + 5 = 17 12 - 5 = 7 12 * 5 = 60 12 / 5 = 2 $
Download : sample-005.c
/*
* 2017/07/07 sample-005.c
*/
/*
* 複数の正の整数の総和を計算する
*
* 利用方法
* コンパイル
* cc -I ~/c/include -c sample-005.c
* リンク
* cc -o sample-005.exe sample-005.c
* 実行
* ./sample-005.exe
*/
#include <stdio.h>
#include "s_print.h"
#include "s_input.h"
/*
正の整数をいくつかキーボードから入力し、
その総和を出力する
ただし、最後に、0 以下の数を入力する
入力は、関数を呼び出す前に行われ、引数に渡される
目的 : 入力(したデータ)を、
終了のためのチェック
加えるデータ
の二ヶ所で利用したい
入力したデータ二ヶ所で利用したいは関数に引数として
わたして、その引数変数を経由して利用するパターンを使う
(注意) 後で、「代入」を学ぶと、もっと簡単になる
引数 :
int pre_input
関数を呼び出すまえに入力されたデータ
int total
これまで、入力されたデータの総和が入っている
入力の例
1 2 3 4 -1
-> 結果の総和として 10 が表示される
*/
void input_sum ( int pre_input, int total ) {
if ( pre_input <= 0 ) { /* 加えるデータはもうない */
/* お仕舞いなので.. */
s_print_string ( "総和は " );
s_print_int ( total );
s_print_string ( " です。\n" );
} else { /* 入力が正なので、まだやる可能性がある */
input_sum ( s_input_int(), total + pre_input );
/*
total にはこれまでの和
pre_input には、今回の入力
なので
ここまでの総和は
total + pre_input
になる
*/
}
}
int main(void) {
input_sum( s_input_int(), 0 );
return 0;
}
12 83 40 58 42 0
$ ./sample-005.exe < sample-005.in 12 83 40 58 42 0 総和は 235 です。 $
Download : sample-006.c
/*
* 2017/07/07 sample-006.c
*/
/*
* rand 関数の利用例
*
* 利用方法
* コンパイル
* cc -I ~/c/include -c sample-006.c
* リンク
* cc -o sample-006.exe sample-006.c
* 実行
* ./sample-006.exe
*/
#include <stdio.h>
#include "s_print.h"
void print_n_random ( int n ) {
if ( n <= 0 ) {
} else {
/* ここから */
s_print_int ( rand() );
s_print_char ( '\n' );
/* ここまでが、 n 回繰り返される */
print_n_random ( n - 1 );
}
}
int main(void) {
print_n_random ( 10 ); /* 10 個の乱数を出力 */
return 0;
}
$ ./sample-006.exe 1804289383 846930886 1681692777 1714636915 1957747793 424238335 719885386 1649760492 596516649 1189641421 $
Download : sample-007.c
/*
* 2017/07/07 sample-007.c
*/
/*
* srand による乱数系列の変更
*
* 利用方法
* コンパイル
* cc -I ~/c/include -c sample-007.c
* リンク
* cc -o sample-007.exe sample-007.c
* 実行
* ./sample-007.exe
*/
#include <stdio.h>
#include "s_print.h"
#include "s_input.h"
int main(void) {
s_print_string ( "乱数の seed(種) を入力してください : " );
srand(s_input_int()); /* キーボードから seed を入力 */
s_print_string ( "1回目 : " );
s_print_int ( rand() );
s_print_char ( '\n' );
s_print_string ( "2回目 : " );
s_print_int ( rand() );
s_print_char ( '\n' );
s_print_string ( "3回目 : " );
s_print_int ( rand() );
s_print_char ( '\n' );
return 0;
}
1234
$ ./sample-007.exe < sample-007.in 乱数の seed(種) を入力してください : 1234 1回目 : 479142414 2回目 : 465566339 3回目 : 961126155 $
Download : sample-008.c
/*
* 2017/07/07 sample-008.c
*/
/*
* 時刻による乱数系列の選択
*
* 利用方法
* コンパイル
* cc -I ~/c/include -c sample-008.c
* リンク
* cc -o sample-008.exe sample-008.c
* 実行
* ./sample-008.exe
*/
#include <stdio.h>
#include "s_print.h"
#include "s_input.h"
int main(void) {
srand(time(NULL)); /* プログラムの実行開始時間を種にする */
//srand(0); /* プログラムをチェックする時は乱数列を固定 */
s_print_string ( "1回目 : " );
s_print_int ( rand() );
s_print_char ( '\n' );
s_print_string ( "2回目 : " );
s_print_int ( rand() );
s_print_char ( '\n' );
s_print_string ( "3回目 : " );
s_print_int ( rand() );
s_print_char ( '\n' );
return 0;
}
$ ./sample-008.exe 1回目 : 1795522165 2回目 : 1816084263 3回目 : 672451354 $
Download : sample-009.c
/*
* 2017/07/07 sample-009.c
*/
/*
* 数当てゲーム
*
* 利用方法
* コンパイル
* cc -I ~/c/include -c sample-009.c
* リンク
* cc -o sample-009.exe sample-009.c
* 実行
* ./sample-009.exe
*/
#include <stdio.h>
#include "s_input.h"
#include "s_print.h"
#include "s_random.h" /* s_random.h を利用してみる */
/*
s_random.h によって、次の関数が利用可能になる
s_random() rand() と同じ、整数の乱数を返す
s_init_random() 時刻を利用して、乱数系列を変更
s_n_random(N) 0 〜 (N-1) の間の整数の乱数を返す
s_random_a_b(A,B) A 〜 B の間の整数の乱数を返す
s_coin() 0(裏) or 1(表) のどちらかを返す
s_dice() 1 〜 6 の間の整数の乱数を返す
*/
/*
プログラムが考えた数 ( 1 〜 100 の乱数 ) を
人間が、予想して、当てるというゲームプログラム
入力する個数は、当るまでなので、何度も入力する必要がある
-> input loop を使う
問題を作るのに乱数を利用する
*/
void game( int input, int question ) {
if ( input == question ) { /* 予想が当っている */
s_print_string ( "おめでとう、ございます。当たりです\n" );
} else {
if ( input > question ) {
s_print_string ( "大きすぎます。\n" );
} else {
s_print_string ( "ちいさすぎます。\n" );
}
s_print_string ( "もう一度予想してください : " );
game( s_input_int(), question );
}
}
/*
* main
*/
int main(int argc, char *argv[]) {
s_init_random(); /* 現在の時刻を利用して乱数を初期化*/
/* 毎回異る問題になる */
s_print_string ( "コンピュータが考えた 1 〜 100 の数を予想して入力してください : " );
game ( s_input_int(), s_random_a_b(1,100) );
}
コンピュータが考えた 1 〜 100 の数を予想して入力してください : 40 40 ちいさすぎます。 もう一度予想してください : 60 60 ちいさすぎます。 もう一度予想してください : 80 80 大きすぎます。 もう一度予想してください : 70 70 大きすぎます。 もう一度予想してください : 65 65 ちいさすぎます。 もう一度予想してください : 68 68 大きすぎます。 もう一度予想してください : 67 67 大きすぎます。 もう一度予想してください : 66 66 おめでとう、ございます。当たりです
Download : sample-010.c
/*
* 2017/07/07 sample-010.c
*/
/*
* 数当て(逆)
*
* 利用方法
* コンパイル
* cc -I ~/c/include -c sample-010.c
* リンク
* cc -o sample-010.exe sample-010.c
* 実行
* ./sample-010.exe
*/
#include <stdio.h>
#include "s_input.h"
#include "s_print.h"
/*
sample-009.c とは逆に、
人間が数を考え、
コンピュータが当てる
*/
/*
考えかた
答えが、区間 [a,b] の中にあるとして、
答の案として x = (a+b)/2 を言う
もし、x が大きい場合は、答えは
区間 [a,x-1] の中にある
逆に、そうでない場合は
区間 [x+1,b] の中にある
にある事がわかる
これをヒントに考える
ルール
コンピュータの予想が正しい時は 0
コンピュータの予想が大きいときは 1
コンピュータの予想が小さいときは 2
を答える
*/
void game ( int ans, int a, int b, int x ) {
if ( ans == 0 ) { /* 当たり */
s_print_string ( "やっぱり " );
s_print_int ( x );
s_print_string ( " でしたか.. 当って嬉しいです\n" );
} else {
if ( ans == 1 ) { /* 予想が大きい */
/* 答えは、区間 [a, x-1] にある.. */
s_print_string ( "私の予想は " );
s_print_int ( (a+(x-1))/2 );
s_print_string ( " です。いかがでしょうか : " );
game(s_input_int(), a, x-1, (a+(x-1))/2 );
} else { /* ans == 2 のはず.. 予想が小さい */
/* 答えは、区間 [x+1,b] にある.. */
s_print_string ( "私の予想は " );
s_print_int ( ((x+1)+b)/2 );
s_print_string ( " です。いかがでしょうか : " );
game(s_input_int(), x+1, b, ((x+1)+b)/2 );
}
}
}
int main(void) {
s_print_string ( "1 〜 100 数を考えてください\n" );
s_print_string ( "私が、その数を予想します\n" );
s_print_string ( "私の予想は 50 です。いかがでしょうか : " );
game ( s_input_int(), 1, 100, 50 );
}
1 2 1 0
$ ./sample-010.exe < sample-010.in 1 〜 100 数を考えてください 私が、その数を予想します 私の予想は 50 です。いかがでしょうか : 1 私の予想は 25 です。いかがでしょうか : 2 私の予想は 37 です。いかがでしょうか : 1 私の予想は 31 です。いかがでしょうか : 0 やっぱり 31 でしたか.. 当って嬉しいです $
Download : sample-011.c
/*
* 2017/07/07 sample-011.c
*/
/*
* 2 のべき乗を順に n 個出力する
*
* 利用方法
* コンパイル
* cc -I ~/c/include -c sample-011.c
* リンク
* cc -o sample-011.exe sample-011.c
* 実行
* ./sample-011.exe
*/
#include <stdio.h>
#include "s_print.h"
#include "s_input.h"
/*
2 のべき乗を順に n 個出力する
*/
void power ( int n, int b ) {
if ( n <= 0 ) {
} else {
s_print_int ( b );
s_print_char ( '\n' );
power ( n - 1, b * 2 );
}
}
/*
* main
*/
int main( int argc, char *argv[] ) {
power ( s_input_int(), 2 );
return 0;
}
10
$ ./sample-011.exe < sample-011.in 10 2 4 8 16 32 64 128 256 512 1024 $
Download : sample-012.c
/*
* 2017/07/07 sample-012.c
*/
/*
* 浮動小数点数の出力
*
* 利用方法
* コンパイル
* cc -I ~/c/include -c sample-012.c
* リンク
* cc -o sample-012.exe sample-012.c
* 実行
* ./sample-012.exe
*/
#include <stdio.h>
#include "s_input.h"
#include "s_print.h"
int main(void) {
s_print_double ( 1.234 ); /* 小数点を含む数が扱える */
s_print_char ( '\n' );
return 0;
}
$ ./sample-012.exe 1.234000 $
Download : sample-013.c
/*
* 2017/07/07 sample-013.c
*/
/*
* 浮動小数点数の入力
*
* 利用方法
* コンパイル
* cc -I ~/c/include -c sample-013.c
* リンク
* cc -o sample-013.exe sample-013.c
* 実行
* ./sample-013.exe
*/
#include <stdio.h>
#include "s_input.h"
#include "s_print.h"
int main(void) {
s_print_double ( s_input_double() );
/* 小数点を含む数を入力して、そのまま出力 */
/* 整数の時には s_print_int ( s_input_int() ); だった */
s_print_char ( '\n' );
return 0;
}
12.34
$ ./sample-013.exe < sample-013.in 12.340000 12.340000 $
Download : sample-014.c
/*
* 2017/07/07 sample-014.c
*/
/*
* 浮動小数点数の計算
*
* 利用方法
* コンパイル
* cc -I ~/c/include -c sample-014.c
* リンク
* cc -o sample-014.exe sample-014.c
* 実行
* ./sample-014.exe
*/
#include <stdio.h>
#include "s_input.h"
#include "s_print.h"
/*
* main
*/
int main( int argc, char *argv[] ) {
s_print_double ( s_input_double() * 1.08 );
/* 小数点を含む数を入力して、消費税込みの値段に.. */
s_print_char ( '\n' );
return 0;
}
123
$ ./sample-014.exe < sample-014.in 123.000000 132.840000 $
Download : sample-015.c
/*
* 2017/07/07 sample-015.c
*/
/*
* s_random.h の利用
*
* 利用方法
* コンパイル
* cc -I ~/c/include -c sample-015.c
* リンク
* cc -o sample-015.exe sample-015.c
* 実行
* ./sample-015.exe
*/
#include <stdio.h>
#include "s_print.h"
#include "s_input.h"
#include "s_random.h"
/*
s_random.h によって、次の関数が利用可能になる
s_random() rand() と同じ、整数の乱数を返す
s_init_random() 時刻を利用して、乱数系列を変更
s_n_random(N) 0 〜 (N-1) の間の整数の乱数を返す
s_random_a_b(A,B) A 〜 B の間の整数の乱数を返す
s_coin() 0(裏) or 1(表) のどちらかを返す
s_dice() 1 〜 6 の間の整数の乱数を返す
*/
/*
* main
*/
int main(int argc, char *argv[]) {
s_init_random(); /* 時計を使って、乱数列を初期化 */
s_print_string ( "1回目 : " );
s_print_int ( s_dice() ); /* サイコロの結果 */
s_print_char ( '\n' );
s_print_string ( "2回目 : " );
s_print_int ( s_dice() );
s_print_char ( '\n' );
s_print_string ( "3回目 : " );
s_print_int ( s_dice() );
s_print_char ( '\n' );
return 0;
}
$ ./sample-015.exe 1回目 : 2 2回目 : 2 3回目 : 4 $
/*
* CDATE FILENAME
*
* 与えられた自然数の素因数を出力する
*
* 12 は..
*
*
*
*
*
*
*/
#include <stdio.h>
#include "s_print.h" /* s_print_int を利用するので.. */
/*
* void print_prime_factor_sequence ( int n, int p )
* 機能 : p 以上の n の素因数を小さい順に並べで表示する
* 条件 : n には p 未満の素因数を含まれていないものとする
* int n : p 未満の素因数を含まれていない自然数
* 返り値 : なし
*/
void print_prime_factor_sequence ( int n, int p ) {
if ( p > n ) { /* もう n には p 以上の素因数を含まない */
/* 何もしなくてよい */
/* 本来、ここにくるのは n = 1 の時だが、念の為 */
} else if ( n % p == 0 ) { /* n が p を素因数として含む */
s_print_char ( ' ' ); /* 隙間を空け */
s_print_int ( p ); /* 素因数を表示し */
/* もう一度 p の要素があるかもしれないので、そこから試す [再帰] */
print_prime_factor_sequence ( n / p, p );
/* n を p で割って、その結果に、さらに p の因数が
あるかどうかを試す */
} else { /* n が p を素因数として含まない */
/* 本来は p の次の素数を試すべきだが.. */
/* その代りに p + 1 を試す (のは無駄だが、正く動く) [再帰] */
/* 本来、次に試すべき値は、p の次の素数であるべき */
/* p+1 を試しだめだったら、次に p+2 と順番に試して
いっても、(無駄があって効率は悪いが..)問題なく動く */
print_prime_factor_sequence ( n, p + 1 );
/*
n は p で割り切れないので、
n を、次は p+1 (素数とは限らない) で試す
*/
}
}
/*
* void print_prime_factor_of ( int n )
* 機能 : n の素因数を出力する
* int n : 素因数を表示したい自然数
* 返り値 : なし
*/
void print_prime_factor_of ( int n ) {
if ( n < 1 ) { /* 与えらた数が自然数ではない */
s_print_int ( n );
s_print_string ( "は、自然数ではありません\n" );
} else if ( n == 1 ) { /* 与えられた数が 1 の場合 */
s_print_int ( n );
s_print_string ( "の素因数はありません\n" );
} else {
s_print_int ( n );
s_print_string ( "の素因数分解は" );
/* n > 1 なので、最初の素数候補 2 を与えて、
素因数分解を開始する */
print_prime_factor_sequence ( n, 2 );
s_print_string ( " となります。\n" );
}
}
/*
* main
*/
int main( void )
{
print_prime_factor_of ( 12 );
print_prime_factor_of ( 600 );
return 0;
}
/*
* 20170707-01-QQQQ.c
*
* 二つの整数値をキーボードから入力し、その四則並びに余りを出力する
*
* コンパイル :
* cc -I ~/include -c 20170707-01-QQQQ.c
* cc -o 20170707-01-QQQQ.exe 20170707-01-QQQQ.o
* 実行 :
* ./20170707-01-QQQQ.exe
*
*/
#include <stdio.h>
#include "s_input.h"
#include "s_print.h"
/*
* print_int_result
*/
void print_int_result ( char *name, int a, int b, char op, int value ) {
/* 例:
和 : 175+51=226
name : 和
a : 175
b : 51
op : '+'
value : 226
*/
s_print_string ( name ); /* 和 */
s_print_string ( " : " );
s_print_int ( a ); /* 175 */
s_print_char ( op ); /* + */
s_print_int ( b ); /* 51 */
s_print_char ( '=' );
s_print_int ( value ); /* 226 */
s_print_newline();
}
/*
* print_int_calc
*/
void print_int_calc ( int a, int b ) {
print_int_result ( "和", a, b, '+', a + b );
print_int_result ( "差", a, b, '-', a - b );
print_int_result ( "積", a, b, '*', a * b );
print_int_result ( "商", a, b, '/', a / b );
print_int_result ( "余り", a, b, '%', a % b );
}
/*
* print_int_calc_1
*/
void print_int_calc_1 ( int a ) {
/* 二つ目の数の入力と、関数呼出し */
print_int_calc ( a, s_input_int() );
}
/*
* main
*/
int main( int argc, char *argv[] )
{
/*
* 複数の入力を伴うので、入力の順序を保証するために、
* 入力してから関数を呼ぶ
*/
/* 一つ目の数の入力と、関数呼出し */
print_int_calc_1 ( s_input_int() );
/*
これを、いきなり
print_int_calc ( s_input_int(), s_input_int() );
とはやってはいけない
why ?
関数の引数が、後ろから評価されるので、
先に入力した値が、後ろに入ってしまうので
順番が逆になってしまう。
※この問題は、後期で学ぶ内容で、解決される
*/
return 0;
}
#include <stdio.h>
#include "s_input.h"
#include "s_print.h"
/*
* print_double_result
*/
void print_double_result ( char *name, double a, double b, char op, double value ) {
s_print_string ( name );
s_print_string ( " : " );
s_print_double ( a ); /* 浮動小数点数型の出力は */
s_print_char ( op ); /* s_print_double を利用 */
s_print_double ( b ); /* 型が違うと、同じ事(出力)でも */
s_print_char ( '=' ); /* 違う関数を呼び出す必要がある */
s_print_double ( value );
s_print_newline();
}
/*
* print_double_calc
*/
void print_double_calc ( double a, double b ) {
/* 関数の引数に浮動小数点を利用する場合は
仮引数変数の型宣言は double を利用する */
/* cf.
整数型の時は int を利用した */
print_double_result ( "和", a, b, '+', a + b );
print_double_result ( "差", a, b, '-', a - b );
print_double_result ( "積", a, b, '*', a * b );
print_double_result ( "商", a, b, '/', a / b );
/*
浮動小数点数では、割り算は、小数点数以下も計算される
ので、余りの計算はしない
小数点以下を切り捨てする関数もある
(興味があるかたは「調べて」ください)
*/
}
/*
* print_double_calc_1
*/
void print_double_calc_1 ( double a ) {
/* 二つ目の数の入力と、関数呼出し */
print_double_calc ( a, s_input_double() );
}
/*
* main
*/
int main( int argc, char *argv[] )
{
/*
* 複数の入力を伴うので、入力の順序を保証するために、
* 入力してから関数を呼ぶ
*/
/* 一つ目の数の入力と、関数呼出し */
print_double_calc_1 ( s_input_double() );
return 0;
}
#include <stdio.h>
/*
double 型 : 浮動小数点数
*/
#include "s_print.h" /* 浮動小数点数の出力 */
int main(int argc, char *argv[] ) {
s_print_string ( "浮動小数点数の出力例 : " );
s_print_double ( 123.456 );
s_print_newline();
s_print_string ( "二つの浮動小数点数 ( 123.456 と 789.012 の四則\n" );
s_print_string ( "和 : 123.456 + 789.012 = " );
s_print_double ( 123.456 + 789.012 ); /* 和の計算 */
s_print_newline();
s_print_string ( "差 : 123.456 - 789.012 = " );
s_print_double ( 123.456 - 789.012 ); /* 差の計算 */
s_print_newline();
s_print_string ( "積 : 123.456 * 789.012 = " );
s_print_double ( 123.456 * 789.012 ); /* 積の計算 */
s_print_newline();
s_print_string ( "商 : 123.456 / 789.012 = " );
s_print_double ( 123.456 / 789.012 ); /* 商の計算 */
s_print_newline();
return 0;
}
#include <stdio.h>
/*
double 型 : 浮動小数点数
*/
#include "s_print.h" /* 浮動小数点数の出力 */
int main(int argc, char *argv[] ) {
s_print_string ( "整数型の割り算 : " );
s_print_int ( 5 / 3 );
s_print_newline();
s_print_string ( "余りは : " );
s_print_int ( 5 % 3 );
s_print_newline();
s_print_string ( "浮動小数点数の割り算 : " );
s_print_double ( 5.0 / 3.0 );
s_print_newline();
return 0;
}
/*
double 型 : 数学ライブラリの利用
数学上の実数関数 : sin, cos, etc.. を利用する場合
1. ソースコード(c ファイル)に #include <math.h> を追加
#include <stdio.h> の次の行と決めておくのが解りやすい
2. リンク時に -lm (l,m は共に小文字)を最後に追加する
コンパイル
cc -I ~/c/include p-003.c
リンク
cc -o p-003.exe p-003.o -lm
実行
./p-003.exe
*/
#include <stdio.h>
#include <math.h> /* 数学ライブラリを利用する場合 */
#include "s_print.h" /* 浮動小数点数の出力 */
int main(int argc, char *argv[] ) {
s_print_string ( "sin(π/4)= : " );
s_print_double ( sin(M_PI/4.0) );
/* sin は、正弦関数 sin */
/* M_PI は、円周率 */
s_print_newline();
s_print_string ( "√2/2= : " );
s_print_double ( sqrt(2.0)/2.0 );
/* sqrt は、平方根を求める関数 */
s_print_newline();
return 0;
}
#include <stdio.h>
#include "s_print.h"
int main(int argc, char *argv[] ) {
/*
sizeof ( 型名 )
この C コンパイラは、「型名」の型が
何 byte で表現されるか
を整数値で返す
- byte 数が多いほど、多くの種類の数が表現可能
例 : 整数型なら、最大最小の値が広くなる
浮動小数点数型なら、最大最小も広くなり、
また、精度(どれだけ細かい幅の数が表せるか ?)
も、よくなる
- C コンパイラによって、この値が異なる
C コンパイラは、それが動く環境で、
最も「自然」なデータを表現するように
設計されている
-> 環境が変わっても、プログラムの変更が少なくて済む
-> システムを記述するのに、便利
OS の記述などに利用され、(古いのに..)いまだに利用される
*/
s_print_string ( "sizeof ( char ) = " );
s_print_int ( sizeof ( char ) );
s_print_newline();
s_print_string ( "sizeof ( int ) = " );
s_print_int ( sizeof ( int ) );
s_print_newline();
/*
sizeof ( int ) -> 4
int は、4 byte = 4 * 8 = 32bit で表現されている
表現できる整数の個数は 2^(32) 個 '=, (2^(10))^3 * 2^2 '=, 40 * 10^8
s_print_string ( "sizeof ( double ) = " );
s_print_int ( sizeof ( double ) );
s_print_newline();
return 0;
}
#include <stdio.h>
#include "s_print.h"
/*
2 べき乗を、指定された数まで出力する
*/
void print_two_power ( int b, int n ) {
if ( n <= 0 ) {
} else {
s_print_int ( b );
s_print_newline();
print_two_power( b * 2, n - 1 );
}
}
int main(int argc, char *argv[] ) {
print_two_power ( 2, 40 );
return 0;
}
#include <stdio.h>
#include "s_print.h"
void sum_inc( double sum, double n, int m ) {
if ( m <= 0 ) {
s_print_doublel ( sum );
s_print_newline();
} else {
sum_inc( sum + 1.0/n, n + 1.0, m - 1 );
}
}
void sum_dec( double sum, double n, int m ) {
if ( m <= 0 ) {
s_print_doublel ( sum );
s_print_newline();
} else {
sum_dec( sum + 1.0/n, n - 1.0, m - 1 );
}
}
int main(int argc, char *argv[] ) {
s_print_string ( "inc sum : " );
sum_inc ( 0.0, 1.0, 1000000 );
/* 1/1 + 1/2 + 1/3 + ... + 1/1000000 */
s_print_string ( "dec sum : " );
sum_dec ( 0.0, 1000000.0, 1000000 );
/* 1/1000000 + 1/999999 + 1/999998 + ... + 1/1 */
return 0;
}
課題
20170630-02 の考え方
「与えられた自然数の素因数を出力する」
-> 素因数分解を行う
#「 数学的」に考える
手順
1. 具体例でやってみる
例 : 50
50 ... 素数である 2 で割り切れる
50 / 2 = 25 .. 2
25 ... 同じ素数である 2 で割り切れない、次に行く
25 ... 次の素数である 3 で割り切れない、次に行く
25 ... 次の素数である 5 で割り切れる
25 / 5 = 5 .. 5
5 ... 同じ素数である 5 で割り切れる
5 / 5 = 1 .. 5
1 は、これ以上、素因数は存在しないので、
これまでの素因数を並べて、終了
2 * 5 * 5
2. 一般化を行う
自然数 n が与えられたら
n を小さい方の素数で割る
割り切れる限り、その素数で割る
割り切れない場合は、次の素数を試す
もし、n が 1 になったら終了
!! 素数を、小さい方から、作る作業が必要
!! それだけでも、大変な内容
3. 「数学的な発想」
自然数の性質
m が n で割り切れて、n が p で割り切れれば、
m は、p 自身で割り切れる
例 : m=12, n=6, p=3
考察
今、p_1=2, p_2=3, ..., p_k が、小さい方からの素数の並び
(定理1) 仮定:自然数 n が、p_1 から p_{k-1}までの素因数を持たない
結論:自然数 n は p_{k-1}+1 から p_k - 1 までの自然数で割り切れない
why (証明)
もし、自然数 n が p_{k-1}+1 <= m < p_k で割り切れたとする
定理 1 から、n は m の素因数で割り切れる
一方、m は、素数でないので、必ず、素因数 p_i を持つ
p_i は、p_1 ? p_{k-1} のいずれかなので、
これは、n が、p_1 ? p_{k-1} までの素因数を持たない事に矛盾
背理法により、n は、p_{k-1}+1 <= m < p_k となる m で割り切れない
例: 50
50 / 2 -> o, 25, 2
25 / 2 -> x
25 / 3 -> x
25 / 4 -> x (かならず、割り切れない)
(やっても、「無駄」だが、
論理上の悪影響はない)
# プログラム上は、「遅く」なる
# という悪影響はある
25 / 5 -> o, 5, 5
5 / 5 -> o, 1, 5
p_{k-1} わりきれなければ、次の素数である、
p_k を試す必要があるが、無駄と解っていても、
p_{k-1}+1 から p_k - 1 までを試しても、問題はない
-> 素数で試すのではなく、自然数を順に試せばよい
-> 「素数を小さいほうから並べる」課題は不要
[浮動小数点数]
C 言語で標準で扱えるデータ構造の一つで、
実数(小数)を表現するデータ構造
型名は「double」を使う
小数の値を表現するために、小数点が利用できる
整数型と浮動小数点数の違い
整数型 浮動小数点数
宣言 int double
値の表現 数字列 小数点数を一つ含む数字列
例 : 123 123.456
-123 -123.456
四則 +,-,*,/ (共通)
(割り算) 結果は整数 結果は浮動小数点数
小数点数以下は 小数点数以下も計算される
切り捨て
余りの演算子(%)がある ない
比較演算 (共通) ==, !=, <, >, <=, >= が使える
浮動小数点数では「==」はつかわない
その代わりに、差の絶対値が小さい数より、
小さい場合を「等しいとみなす」
入出力
共通で、当分は s_input.h, s_print.h を利用
出力 s_print_int s_print_double
入力 s_input_int s_input_double
計算結果 正確に計算される 計算誤差が入る
本質的に無限なものを有限で表した結果
ライブラリ 共通で色々あるが..
数学関数ライブラリがある
実数上の関数 sin, cos, exp, .. がある
5.0/3.0 = 1.666... (無限小数になる)
計算機では、「無限」は扱えない
ある範囲で、切り捨て(四捨五入)がなされる
結果的に 1.66667 のようになる
計算に誤差が含まれる
Download : 20170707-01.c
/*
* 20170707-01-QQQQ.c
*
* 二つの整数値をキーボードから入力し、その四則並びに余りを出力する
*
* コンパイル :
* cc -I ~/c/include -c 20170707-01-QQQQ.c
* cc -o 20170707-01-QQQQ.exe 20170707-01-QQQQ.o
* 実行 :
* ./20170707-01-QQQQ.exe
*
*/
#include <stdio.h>
#include "s_input.h"
#include "s_print.h"
/*
* print_int_result
*/
void print_int_result ( char *name, int a, int b, char op, int value ) {
s_print_string ( name );
s_print_string ( " : " );
s_print_int ( a );
/*
** この部分を完成させなさい
*/
s_print_char ( '=' );
s_print_int ( value );
s_print_newline();
}
/*
* print_int_calc
*/
void print_int_calc ( int a, int b ) {
print_int_result ( "和", a, b, '+', a + b );
print_int_result ( "差", a, b, '-', a - b );
/*
** この部分を完成させなさい
*/
print_int_result ( "余り", a, b, '%', a % b );
}
/*
* print_int_calc_1
*/
void print_int_calc_1 ( int a ) {
/* 二つ目の数の入力と、関数呼出し */
print_int_calc ( a, s_input_int() );
}
/*
* main
*/
int main( int argc, char *argv[] )
{
/*
* 複数の入力を伴うので、入力の順序を保証するために、
* 入力してから関数を呼ぶ
*/
/* 一つ目の数の入力と、関数呼出し */
print_int_calc_1 ( s_input_int() );
return 0;
}
175 51
$ ./20170707-01-QQQQ.exe 175 51 和 : 175+51=226 差 : 175-51=124 積 : 175*51=8925 商 : 175/51=3 余り : 175%51=22 $
Download : 20170707-02.c
/*
* 20160708-02-QQQQ.c
*
* 二つの浮動小数点数値をキーボードから入力し、その四則を出力する
*
* コンパイル :
* cc -I ~/c/include -c 20160708-02-QQQQ.c
* cc -o 20160708-02-QQQQ.exe 20160708-02-QQQQ.o
* 実行 :
* ./20160708-02-QQQQ.exe
*
*/
#include <stdio.h>
#include "s_input.h"
#include "s_print.h"
/*
* print_double_result
*/
void print_double_result ( char *name, double a, double b, char op, double value ) {
s_print_string ( name );
s_print_string ( " : " );
s_print_double ( a );
/*
** この部分を完成させなさい
*/
s_print_char ( '=' );
s_print_double ( value );
s_print_newline();
}
/*
* print_double_calc
*/
void print_double_calc ( double a, double b ) {
print_double_result ( "和", a, b, '+', a + b );
print_double_result ( "差", a, b, '-', a - b );
/*
** この部分を完成させなさい
*/
}
/*
* print_double_calc_1
*/
void print_double_calc_1 ( double a ) {
/* 二つ目の数の入力と、関数呼出し */
print_double_calc ( a, s_input_double() );
}
/*
* main
*/
int main( int argc, char *argv[] )
{
/*
* 複数の入力を伴うので、入力の順序を保証するために、
* 入力してから関数を呼ぶ
*/
/* 一つ目の数の入力と、関数呼出し */
print_double_calc_1 ( s_input_double() );
return 0;
}
123.456 789.012
$ ./20170707-02-QQQQ.exe 123.456000 789.012000 和 : 123.456000+789.012000=912.468000 差 : 123.456000-789.012000=-665.556000 積 : 123.456000*789.012000=97408.265472 商 : 123.456000/789.012000=0.156469 $