サンプル・プログラムの実行例
サンプル・プログラムのダウンロード
isCirculatingDecimal.php | サンプル・プログラム本体 |
pahooInputData.php | データ入力に関わる関数群。 使い方は「数値入力とバリデーション」「文字入力とバリデーション」などを参照。include_path が通ったディレクトリに配置すること。 |
pahooDataStructure.php | データ構造に関わるクラス。 分数クラス pahooFrac の使い方は「PHPによる分数クラスの作成」を参照。include_path が通ったディレクトリに配置すること。 |
バージョン | 更新日 | 内容 |
---|---|---|
1.1.0 | 2020/02/11 | pahooInputData導入,入力バリデーション強化 |
1.0 | 2020/02/11 | 初版 |
バージョン | 更新日 | 内容 |
---|---|---|
1.5.0 | 2024/01/28 | exitIfExceedVersion() 追加 |
1.4.2 | 2024/01/28 | exitIfLessVersion() メッセージ修正 |
1.4.1 | 2023/09/30 | コメントの訂正 |
1.4.0 | 2023/09/09 | $_GET, $_POST参照をfilter_input()関数に置換 |
1.3.0 | 2023/07/11 | roundFloat() 追加 |
バージョン | 更新日 | 内容 |
---|---|---|
5.4 | 2022/09/26 | list() → list3() メソッド名変更 |
5.3 | 2022/05/15 | pahooHeapクラス追加 |
5.21 | 2018/08/25 | サマータイム対応 |
5.2 | 2018/07/28 | pahooAVLtreeクラス追加 |
5.1 | 2018/07/24 | pahooBStreeクラス追加 |
小数の2進数表記
\( \begin{eqnarray}
0.5 &=& 5\times10^{-1} \\
0.25 &=& 2\times10^{-1} + 5\times10^{-2} \\
0.375 &=& 3\times10^{-1} + 7\times10^{-2} + 5\times10^{-3}
\end{eqnarray} \)
つぎに10進数の小数を2進数の小数に変換してみよう――
\( \begin{eqnarray}
0.5 &=& 1\times2^{-1} \\
0.25 &=& 0\times2^{-1} + 1\times2^{-2} \\
0.375 &=& 0\times2^{-1} + 1\times2^{-2} + 1\times2^{-3} \\
\end{eqnarray} \)
つまり、2進数に変換したときに循環小数にならないケースは、通分して、分母が2のべき乗になるケースに限られる。
PHPで分数を扱うクラス pahooFrac は「PHPによる分数クラスの作成」で紹介したとおりだ。このクラスを使い、10進小数の分母を10のべき乗に設定し、それを約分して分母が2のべき乗にならなければ循環小数と判定する。
解説:初期値など
10進数の小数部を取り出し、対数計算などを行う関係上、ここで誤差が発生しないように扱える最小の小数桁数を MAX_DECIMAL として制限しておく。
55: //表示幅(ピクセル)
56: define('WIDTH', 600);
57:
58: //入力小数(初期値)
59: define('DEF_NUMBER', '1.05');
60:
61: //扱える最小の小数桁数(10進数)
62: define('MAX_DECIMAL', 8);
63:
64: //データ構造クラス
65: require_once('pahooDataStructure.php');
解説:2進数の循環小数かどうか判定する
前半は入力データを検査し、後半で2進数の循環小数かどうかを判定する。
139: /**
140: * 2進数の循環小数かどうか判定する
141: * @param string $number 判定する小数
142: * @param string $frac 分数を格納
143: * @param string $errmsg エラーメッセージ格納
144: * @return bool TRUE:循環小数である/FALSE:循環小数でないまたはエラー
145: */
146: function isCirculatingDecimal($number, &$frac, &$errmsg) {
147: $errmsg = '';
148:
149: //入力データ検査
150: if (preg_match('/^([\-|\+]*[0-9]*)\.*([0-9]*)/ui', $number, $arr) == 0) {
151: $errmsg = '入力値が小数ではありません';
152: return FALSE;
153: }
154:
155: //小数部があるかどうか
156: if (! isset($arr[2])) return FALSE;
157:
158: //入力データ検査
159: $dec = $arr[2];
160: if (strlen($dec) > MAX_DECIMAL) {
161: $errmsg = '入力できるのは小数第' . MAX_DECIMAL . '位までです';
162: return FALSE;
163: }
164:
165: //2進数の循環小数かどうか判定
166: $pf = new pahooFrac($dec, pow(10, strlen($dec))); //分数クラス
167: $pf->reduce(); //約分
168: $frac = $pf->printFrac();
169: $res = log($pf->denominator, 2); //分母が2のべき乗かどうか
170: $res = $res - floor($res);
171: $pf = NULL;
172:
173: return ($res != 0);
174: }
参考サイト
- 有限小数、循環小数、分数、無理数:ぱふぅ家のホームページ
コンピュータは内部演算を2進数で行っているが、10進数の小数を2進数に変換したとき、循環小数になるものが多い。たとえば、0.5,0.6,0.7は、すべて2進数の循環小数になる。
循環小数があると、10進数では演算誤差がなかったのに、コンピュータの計算結果は予期せぬ演算誤差を発生させることになる。
そこで今回は、入力された小数が2進数の循環小数かどうかを判定するプログラムを作ってみることにする。
(2024年1月27日)pahooInputData導入,入力バリデーション強化,TeX画像をMathJaxに置き換え