◎第7回 数値データの扱い

データ型とデータの表現

下へ一覧へ
○テキスト
4章(4.1)
型:数・文字など表現対象と計算機内部表現の対応方法
   型が違うと演算方法が違う。(そもそも可能な演算が違う。)

下へ上へ 基本である数とその表現 人間は10進数(decimal number) 各桁は 0から9 ディジタル計算機内部では2進数(binary number)を使っている。 2進の桁 ( binary digit = bit )は、0 または、1である。 10 進数の 3452 は、 3×10の3乗 + 4×10の2乗 + 5×10の1乗 + 2×10の0乗 を意味している。 2 進数の 1100 は、 1×2の3乗 + 1×2の2乗 + 0×2の1乗 + 0×2の0乗 1×8 + 1×4 + 0×2 + 0×1 = 12(10進数) を意味している。 ************ の星の数は 十進法を用いると 1 と 2 を並べて表記する。 二進法を用いると 1 と 1 と 0 と 0 をこの順に並べて表記する。 n 進数の n は 基数(radix)とよぶ。 ( 基数の変換 )
下へ上へ 2進数は桁数が多く人間には扱いにくい 10進数と2進数は変換が面倒 8進数 (octal number) 2進数の3桁 (3 bit )毎に区切って扱う 各桁は 0 から 7 の数字で表す。 2進数と8進数の変換は、桁毎に行えばよい 16進数 (hexadecimal number) 2進数の4桁 (4 bit )毎に区切って扱う 各桁は 0 から 9 の数字と6つのアルファベットの AからF を用いて 表す。A は 10, B は 11, F は 15 などと対応づける。 2進数と16進数の変換は、桁毎に行えばよい。
下へ上へ 「型」 整数と実数(浮動小数点) 整数 integer C int型 (pascal integer 型) 有限の桁:例えば 10進数6桁なら 0〜 10の6乗-1 =(999999) 実数 real C float または double (pascal の real型) 実数の近似値 10進数の場合 浮動小数点数(m×10のe乗) 例 6.22 × 10の22乗 有限の桁の m と eで表す。
下へ上へ 表現できる範囲(整数型) 32 ビット (16ビット) 0〜2の32乗-1 (0〜2の16乗-1) この範囲を超えるものは整数として扱えない→桁あふれ(overflow) 零か正:符号なし整数 (unsigned integer) 負の数の扱い すぐに考えつく方法:符号と絶対値 符号も 0,1 で表記する。 0 for + / 1 for - 32ビットの内 1ビットを符号に使う絶対値は31ビット 形式的に +0 と -0 がある。 実は符号+絶対値は計算機の中ではあまり使わない。 演算回路の簡単化のため負数は「補数」で表記する。 符号つき整数の表現できる範囲 32 ビット (16ビット) -(2の31乗)〜2の31乗-1 (-(2の15乗)〜2の15乗-1) -32768 32767 ここの Cの場合、 long int 32 ビット符号付 単に int と書くと long int のこと short int 16 ビット符号付 (パソコンでは 単に int と書くとこれ) char 8 ビット符号付 (主に文字を表すのに用いる(次回に詳述)) unsigned long 32ビット符号なし整数
下へ上へ 実数の表現の準備 10進数の小数 0.987 9×10の-1乗+8×10の-2乗+7×10の-3乗 2進数の小数 0.101 1× 2の-1乗+0× 2の-2乗+1× 2の-3乗 注意事項 1/3は10進数では循環小数となる。0.33333333..... 1/5は2進数では循環小数となる。 0.00110011..... 計算機内部の表現 浮動小数点数 m×2のe乗 有限ビットの mとeで表す。実数の近似値。 仮数と指数(10進数) s×a.mmm...×10のe乗 s=1 or -1 a≠0 2進数(基数は2) s×a.mmm...×2のe乗 s=1 or -1 a≠0すなわち a=1 a≠0すなわち a=1 常に 1 なので省略可能(暗黙の1) ただし、0(zero)はa=1にできないので特殊扱い (注: 上の表記で mmm... はすべて同じ数字という意味ではない )
下へ上へ 近似値→誤差がある 仮数部のビット数(桁数)が多い程誤差が小さい 2 は10の約0.3乗( log 2 ≒ 0.3010...)なので、 nビットは10進数で約 0.3*n 桁 指数部のビット数多いほど表現範囲が広い 計算結果でa=1 にできない絶対値の小さな数が得られる:アンダーフロー (1.0 × 2の「eの最小値」乗 より小さい数)(真の 0 は除く) 計算結果で表現できない絶対値の大きな数が得られる:オーバーフロー (1.1〜1×2の「eの最大値」乗より大きい数) ここの Cの場合、 float 型 符号 ( 1 ビット、指数 8 ビット、仮数 24 ビット ) 全32ビット double 型 符号 ( 1 ビット、指数 11 ビット、仮数 53 ビット ) 全64ビット この仮数のビット数は「暗黙の1」を含む また、2のe乗に対して指数部の実際のデータは、e+e0 である。 ( float では、e0=127, double では、e0=1023 )
2進数による内部表現は人間は理解しにくいので、その数に対応する10進数表 現の文字列との間で変換を行なって入出力する。 「数値そのもの」と「内部表現(2進数)」と「文字列表現」を区別し これらの間の関係を理解することが大事である。 文字や文字列の扱いについては、次回説明する予定である。
下へ上へ 定数や変数と型 定数 プログラムの実行中を通して値を変えられない 1 や 1234 整数型の定数 1.0 や 1.234 浮動小数点型の定数 浮動小数点型の定数を指数付で表す事もできる。 たとえば 「1.6 × 10の-19 乗」は、1.6e-19 と書く 変数 主記憶装置(メモリ)内に確保したデータの記憶領域 記憶装置内の位置をアドレスと呼ぶ。 英字で名前をつけて取り扱う。 ( 変数のアドレスの制限 )
下へ上へ 宣言 変数の名前、型の対応を付け、記憶場所を確保する。 C言語では、ブロックの先頭で、変数の宣言ができる。 その変数は宣言のあるブロックの内側だけで有効である。(局所変数,ローカル変数) 例 int i; /* 整数型(int型)の変数 i を宣言する */ double x; /* 倍精度浮動小数点型(double 型)の変数 x を宣言する */ char c; /* 8ビット整数型(char型)の変数 c を宣言する */ (他にはアドレスをデータとして扱うポインタ型があり C では 重要であるが、ここでは説明しない。) (C言語では他に、関数の外すなわち、ブロックの外で宣言する大域変数があるが、 それは、後の「第10回手続き」で言及する)
下へ上へ 型変換 数値を表す型どうしでも、演算を行なう具体的方法が違うので、 場合によって、別の型に変換する必要がある。 自動変換1 代入するときには、自動的に型が変換される。 自動変換2 型の違う値どうしの演算は、演算は一般には精度の高い方に変換して から行なわれる。 ただし、C では、float 同士でも double に変換してから演算される。 自動変換は、変換がどのように行なわれるかを、よく理解していないと 間違った結果を生じるので十分に注意する。 強制型変換 強制的に型を変換するには C では、型キャストを用いる。 関数呼び出しのときも型の変換が必要な場合がある。 関数と型
表現精度による問題 数値は有限の桁で計算しているために、一見正しいアルゴリズムでも 正しい結果を得られないことがある。 ・近い二つの値を引き算すると精度が悪くなる。 例 1.00000090 - 1.00000000 → 0.00000090 ^^^^^^^^^^   ^^ 有効桁数が減る。
下へ上へ ○演習 1. 自分の学籍番号を 2 進数, 8進数, 16 進数でそれぞれ表せ。 それは、short int で表現できるか? 2. 平成 9 年度の政府の予算は 77,390,004×百万円(*)である。 それは、long int で表現できるか? (*)大蔵省のWWWより 3.数値は有限の桁で計算しているために、一見正しいアルゴリズムでも 正しい結果を得られないことがある。このことを次の各例により確認せよ。 3.1 次のプログラムは、第 4 回の数値積分プログラムのループ繰り返し条件を 変更したものである。 a=0 , b=1 , h=0.1 で実行し、停止しないことを確認せよ。また、停止しない理由を考察せよ。 ( コンパイル実行して、from ? に対して 0 と入力し、 to に対して 1、step に対して 0.1 と入力する。強制的に終了させるには ctrl-C をおす ) integral7.c 3.2 2次方程式の解の例 2次方程式の解の公式で -b と sqrt( b*b -4*a*c ) の絶対値が近い場合、 2解の一方で、近い二つの値を引き算して精度が悪くなることが起きる。 これを改善するには、まず絶対値の大きな解を求め、 次に「解と係数の関係 x1*x2=c/a」 を用いて他方の解を求めると よい。両方法を比較して解を求めるプログラムが quad7a.c である。( PAD )コンパイル・実行して a=1 b=2 c=1e-6 の場合について確かめよ。 (1e-6 は 1×10 の-6乗を意味する) このプログラムでは、それぞれの解のあと誤差を()内に表示する。 ( 誤差はその解を、方程式 の左辺から右辺を引いた式に 代入して計算した結果 ) 下へ上へ 3.3 微分方程式の数値解法の例 微分方程式( differential equation )を数値計算で 近似的に解くことができる。 ( numerical solution ←→ 解析解 analytical solution) その方法の一つに、Euler法(オイラー法)がある。 (Euler法の説明(ps file)) 理論上は近似計算の幅Δtを小さくすると計算精度はよくなるが、 実際には必ずしもそうとはいえない。 電気回路の動作を表す微分方程式の近似解を数値的に求めるプログラム diffeq.c( PAD psfile) を用い、次の数値を入力して計算結果を比較し、上のことを確認せよ。 また、この場合、適切な計算時間間隔は何秒か? 時定数 1 秒 電圧源 0 V 初期値 10 V 時間 1秒 計算の時間間隔 ( 0.1 / 1e-3 / 1e-6 / 1e-7 / 1e-8 ) 秒 表示の時間間隔 0.1 秒 (注意: 計算の時間幅を小さくすると計算時間が非常に長くかかる。 この場合は最後に、次の様なプログラムの実行時間が表示されることがある。 322.900u 0.280s 6:35.47 81.7% 0+151k 0+1io 0pf+0w これは 1e-8 で計算した場合の例で、次の様な意味である。 計算そのものに要した時間 322.9秒 Unix の内部処理に要した時間 0.28秒 経過時間 6分35秒 ) 結果をグラフにプロットするには、gnuplot を用いることができる。 gnuplot がうまくいかない場合は、データを表示あるいは印刷して、 手でグラフ用紙にプロットしてよい。
一覧へ上へ ○レポート課題(解答) 1. 10進数(学籍番号の下3桁)+97 の逆数を2進数の小数で表せ。 (有効桁数 2進数8ビット) また、仮数部 7 ビットの2進数浮動小数点表示で表せ。 (指数部は10進数でよい) ヒント:目的の数を2進数で表し 1÷(その数)を2進数で計算すればよい。 この場合は小数点以下必要な桁まで計算する。 2. 上の diffeq において 時定数 0.1 秒 / 電圧源 0 V / 初期値 10 V 時間 0.1 秒 / 計算時間間隔 ( 0.01 / 1e-3 / 1e-6 / 1e-7 / 1e-8 / 1e-9 ) 表示の時間間隔 0.01 秒 で計算し、これらの計算時間間隔の中で 精度の観点から最適なものを求めよ。 また、最適な計算時間間隔と時定数の関係を考察せよ。
一覧へ