以下の課題問題を解き、レポートとして提出せよ。
input number=3.141592 (斜字体部分はユーザーの入力) v=3.141592
おおまかには、以下のようなアルゴリズムに従ったコードを書けば実現できる。
整数部と小数部を別々に処理する 最初は整数部の処理 ・ 1文字読み込む ・ 数字かどうかを検査する 数字ならば数値に変換し、足し合わせる (前の値を10倍して今の値を足し込む) これを "." (ピリオド、小数点)または数字以外の文字が現われるまで繰り返す "." (ピリオド、小数点)が現われた場合は小数部の処理に移る (そうでない場合は小数部はないので整数部だけでおわり) 小数部の処理 ・ 1文字読み込む ・ 数字かどうかを検査する 数字ならば数値に変換し、足し合わせる (1文字進む毎に1桁ずつ小さい値にしながら値を足し込む) これを数字以外の文字が現われるまで繰り返す 最後に整数部の値と小数部の値を足す
プログラムへの入力として以下に示すような場合を試すこと。
それぞれの結果について考察すること。
(何故そういう結果になったのかを説明する、等)
入力文字列 | (条件) |
25 | (整数のみ) |
19.19825 | (浮動小数点数) |
0.11235 | (小数部分のみ) |
2816. | (小数点より後の小数部がない) |
.314 | (小数点より前の整数部がない) |
1.2a3b5d | (数字以外の文字を含む) |
3..221 | (連続した小数点を含む) |
9.2.3 | (2個所で小数点を含む) |
1 . 04 | (途中に空白を含む) |
注意:本課題プログラムについて、scanf()やatof()
などの同様の処理を行なうライブラリ関数を使用しないこと。
補足
C言語では整数と整数の演算の結果は整数になるため、
例えば、"1/10"と書いても 0.1という浮動小数点数にはならず、
0という整数値になる。
(分母も分子も整数なので結果も整数になるため)
この場合、"1.0/10"などのように、式の一部(あるいは全部)に
浮動小数点数を含めることで、0.1を表現できる。
(もちろん直接 "0.1"と書いてもよい)
double v = 1/10; /* 0になる */ double w = 1.0/10; /* 0.1になる */
同じことが整数の変数の場合にも起こるので注意すること。
特に int型の変数同士の除算の場合に見落としがちである。
補足2
浮動小数点数を扱うため数値を格納する変数を int型から float型または double型にする。
printf() を使って表示するときの書式に注意する。
(書式指定子として浮動小数点数を表示する "%f"や "%g"などを指定すること)
オプション課題
以下の改良を加えよ。
ヒント:大文字と小文字の区別をしない比較を行なうには検査する文字を
大文字か小文字に変換してから比較を行なえばよい。
例えば、以下のような"You should backup your data files."
という文字列と検索文字列として"you"が与えられたときに、
前者に後者が含まれているかどうかを検査する。
この場合、先頭の "You"と途中の"you"の2個所が一致するので両方を表示する。
string="You should backup your data files." pattern="you" found at 0 found at 18 (含まれる場合は、その場所(先頭を0として何文字目か)を表示する)
string="You should backup your data files." pattern="my" (含まれない場合は、何も表示しない)
プログラムの雛型をここに置いておくので、
このプログラムをベースにして必要なコードを追加すること。
関数 search_string()の中身を作ればよい。
(main関数の中身は気にしなくてよい)
注意:本課題プログラムについて、str で始まる名前を持つ文字列データ 操作ライブラリ関数(strcmp() など)を使わないこと。 toupper() や tolower() などの文字型データ操作ライブラリ関数は使用してよい。
文字列検索のアルゴリズムは何を使ってもよい。
ここに説明している通りの簡単な方法でもよい。
ただし、この方法は無駄な比較が多く効率が悪い。
文字列探索の効率的なアルゴリズムとしては
KMP (Knuth-Morris-Pratt)法や BM (Boyer-Moore)法が有名である。
(ただし、処理内容は複雑である)
オプション課題
上記プログラムを機能拡張する。
string="You should backup your data files." pattern="you" found at 0 found at 18 total 2 time(s)
string="You should backup your data files." pattern="you" found at 0 found at 18 You should backup your data files. ^^^ ^^^
string="You should turn on your computer." pattern="on" replace="off" You should turn off your computer.
/* 有理数(分数)を表現する構造体 */ typedef struct rational_number { int numer; /* 分子 (numerator) */ int denom; /* 分母 (denominator) */ } rational_number;
ただし、負の値の場合には常に分子側に '-'(マイナス符号)が表示されるようにすること。
(つまり、分母側の値は必ず正の値として表示するということ)
また、表示する際に既約分数として表示すること。
ヒント:既約分数にするには分母と分子をお互いの最大公約数で割ればよい。
最大公約数の求める方法としては「ユークリッドの互除法」が有名である。
(「ユークリッドの互除法」については
プロ演1の課題1を思い出すこと。
プログラムの見通しをよくするため、二つの整数の最大公約数を求める関数 int gcd(int a, int b)
を作るとよい)
プログラムの雛型をここに置いておくので、
このプログラムをベースにして必要なコードを追加するとよい。
以下は実行例である。入力する数値をいろいろ変えてみること。
(最低3パターンを試すこと)
input number (a.numer) = 10 input number (a.denom) = 20 input number (b.numer) = 30 input number (b.denom) = 40 [ 1/2 ] + [ 3/4 ] = [ 5/4 ] [ 1/2 ] - [ 3/4 ] = [ -1/4 ] [ 1/2 ] * [ 3/4 ] = [ 3/8 ] [ 1/2 ] / [ 3/4 ] = [ 2/3 ]
オプション課題
プログラムを機能拡張する。
(どういう拡張を行なったかをきちんと説明すること)
例えば、
分母や分子の値に誤って浮動小数点数などが入力された場合にエラーとして
報告したり、同等の有理数に変換して処理を継続するなどの改良を行なう、
などが考えられる。(これに限らず他の機能拡張でもよい)
input number (a.numer) = 1000000 input number (a.denom) = 2000000 input number (b.numer) = 3000000 input number (b.denom) = 4000000
もし、実行結果が期待されるものと異なる場合には何故そうなるのかを考察せよ。
ヒント:演習で使用している windows PCにおいて、
int型の変数が表現可能な値の範囲は
-2147483648(-231)〜2147483647(231-1)である。
余力があれば、期待される動作をするプログラムにするためには
どうしたらよいかを検討すること。
注意:これはプログラムの作り方によって予想外の動作をする例であるので、
結果がおかしいからといって課題3のプログラムが完成していないわけではない。
課題3においては入力値が4桁までの範囲で期待通りの結果になればよいものとする。
オプション課題
最初の課題プログラム(入力された数字を浮動小数点数に変換する
プログラム)において入力桁数を大きくするとどうなるかを予想し、
実際の結果と比較せよ。
もし、実行結果が期待されるものと異なる場合には何故そうなるのかを考察せよ。