計算機言語 I 第 13 回 浮動小数点数と数学関数
この講義資料は
,
次の場所にあります.
http://www.math.u-ryukyu.ac.jp/~suga/gengo/2018-1/13.pdf
1
浮動小数点数科学技術計算においては
,
小数点付きの数の計算が通常になります.
また,
自然界にある定数には,
アボガド ロ数のような大きな数や,
プランク定数のように0
にとても近い数があります.
これらの数は, 6.02 × 10
23や6.63 × 10
−34(Js)
のような書かれ方をします.
これが浮動小数点数といわれるものです. (
浮動 小数点なので,
小数点の位置が動くように思えますが,
むしろ,
小数点の場所は固定されている,
対義語として,
固定小数点数 というのがあるのですが,
こちらは小数点の場所が動く.) 6.02 × 10
23において, 6.02
を仮数部, 10
23を指数部 と言います.
人間の都合で,
上の数は10
進法になっていますが,
今のコンピュータでは,
仮数部,
指数部ともに2
進法になっています(
過去には, 2
進でないものもあったらしい).
コンピュータは計算機であり
,
そもそもこのような数を計算する目的で開発されました.
現在のコンピュータはディジタルですので
,
数学のような連続的な実数を扱うことはできません.
したがっ て,
浮動小数点数も有限の桁数と範囲を持つ数体系となっています.
ただし,
浮動小数点型は整数型と違い,
計 算結果の桁あふれ(overflow,
結果の絶対値が,
扱える範囲を越える),
桁落ち(underflow,
結果の精度が絶対値 の最小数より小さくなる)
などを検知する仕組み,
および,
最後の桁の4
捨5入に備えた計算などをサポート しています.
C
における浮動小数点数型現在の
C
コンパイラでは, float, double, long double
の浮動小数点が扱えます.
これらの精度は処理系 依存で,
float
のビット幅≤ double
のビット幅≤ long double
のビット幅 が規格として定めらています.
これらのうち
, float, double
は,
下にあるIEEE-754
*1 の規格がde facto Standard(
デファクトスタン ダード,
事実上の標準)
です.
下の表で仮数部が22+1
ビットの意味は, 2
の補数を利用するため, 1
ビットが符 号を表すからです.
指数部は2
の補数ではなく,
符号ビットを使います.
詳しく知りたい人は,
ネットなり,
数*1The Institute of Electrical and Electronics Engineers
値解析の本なりを調べてください
.
型 フォーマット ビット幅 仮数部
(2
進)
精度(10
進換算)
float IEEE-754
単精度32
ビット22+1
ビット 約7
桁double IEEE-754
倍精度64
ビット52+1
ビット 約16
桁long double
はIEEE-754
の4
倍精度(128
ビット)
だったり, 80
ビット(
拡張倍精度)
だったりで,
処理 系により様々です.
この講義で用いる処理系は, 80
ビットのようです.
浮動小数点数の計算
(a × 10
b) × (c × 10
d) = ac × 10
b+dですから
,
浮動小数点数の積(
商)
は,
仮数部の積(
商)
と指数部の指数の和(
差)
に分解して計算できます.
し たがって,
仮数部,
指数部を取り出してきて,
それぞれに対して必要な演算を施せば良いことがわかります.
和
(
差)
は,
少し面倒になります.
例えば, 1.0 + 2.0E-2 = 1.00 + 0.02 = 1.02
ですから
,
指数部の値を一致させて,
絶対値の小さい方をその分桁を右にずらした後,
仮数部の和(
差)
を計算 します.
ずらす桁数は,
指数部の差に一致することに注意してください.
桁をずらす際に,
小さい方の小数部分 の下位の桁は,
保持することができなくなるので,
通常は, 4
捨5
入されます.
このような計算で発生する誤差 を丸め誤差と言います.
ところで
,
上は10
進法で計算しましたが,
コンピュータでは指数部仮数部ともに2
進法で,
そうすることに より, 10
進法と計算のアルゴリズムは同じになります.
さて上のような計算をするには
,
「仮数部,
指数部を取り出す」という操作と,
「仮数部の桁をずらす」とい う操作が必要になります.
これらの操作を実現しているのが,
教科書p. 188
からp. 193
に書かれている,
「ビット単位の論理演算」と「シフト演算」です
.
多くのプログラミング言語では,
このような操作をすること は,
あまり想定してません.
通常のプログラミングで,
このような操作をすることはほとんどないからです. C
はOS
の開発言語として作られたため,
このような操作が簡単にできるようになっています.
ビット単位の論理演算は
,
各ビットで,
論理和,
論理積,
排他的論理和,
否定(0, 1
の反転)
を計算するもので す.
それらの定義の意味は, (
排他的論理和以外は)
数理の皆さんには,
解説をする必要はないでしょう.
例えば
, IEEE-754 32
ビットfloat
では,
上位9
桁が指数部です.
これを, 32
ビットの整数型にするには, 11111111100000000000000000000000=0xff800000
とビット単位の論理積を取る→
23
ビット右にシフトする.
という操作で得られるわけです.
教科書
p. 189, List 7-6, p.191, List 7-7
を実行してみてください.
C
での浮動小数点数の表記簡単な浮動小数点数は
,
小数点を利用して記述すれば良いのは,
見たとおりです.
アボガドロ数のような数の 表記は,
6.02E23
または6.02e23
のように
,
指数部の値の前にE
またはe
を記述します(exponent
のe).
上のように記述した浮動小数点数は, double
型とコンパイラは解釈します. float
型と解釈させるには,
最後にF
またはf
をつけて, 6.02e23f
のように記述し, long double
と解釈させるときは,
最後にL
またはl
をつけて, 6.02e23l
のように記述し ます.
以前にも述べましたが
,
現在では,
特別なことがない限り浮動小数店型はdouble
を利用します.
現在の多 くのコンピュータでは, dobule
型が最も早く計算できるようにCPU
やライブラリ関数が作られています.
printf, scanf
printf
での浮動小数点数の表示は, %f, %e, %E, %g
でdouble
型の表示を意味し, float
はこれを利用す ると自動的にdouble
型にキャストして表示してくれます. %f
は,
絶対値が大きすぎたり小さすぎたりしな い時の表示で,
桁数指定は例えば, %3.1f
とすると, 3
桁で,
小数点以下が1
桁という意味になります. %E, %e
はアボガドロ数のような表示方法です. %g
は, %f
と%e
を数値によって適当に使い分けて表示してくれます. long double
を表示させるには, %Lf
のように, L
を付けます.
scanf
では, %f
はfloat
型の読み込みになります. double
型は, %lf, long double
型は, %Lf
となり ます.
2
数学関数ライブラリ科学技術計算でよく用いられる初等関数
, sin, cos, tan, log
などは,
数学関数ライブラリというものにまと められています.
これらの関数を利用するには,
これらの関数のプロトタイプ宣言が記述されている, math.h
を読み込んでおく必要があります.
#include <math.h>
さらに
,
数学関数ライブラリを利用するには,
コンパイル時にオプション-lm
をつける必要があります. -lm
はld (
リンクエディタ)
に数学関数ライブラリ/usr/lib/libm.a
をリンクするように指示するオプションです.
cc list.c -lm
数学関数ライブラリには
, 3
角関数,
双曲線関数,
指数関数,
対数関数などの初等関数以外にも,
様々な関数が 存在します.
どのような関数があるかは, /usr/include/bits/mathcalls.h
を読めばわかります.
このファ イルは, /usr/include/math.h
でinclude
されます.
関数名のルールとして
,
デフォルトはdouble
型で, float
型は最後にf, long double
型は最後にl
が 付きます.
例えば, sin
はdouble
型を引数にして, double
型を返す関数で,
そのfloat
型版は, sinf,
long double
版は, sinl
となります.
教科書
p.201, List 7-10
から,
教科書p. 203, List 7-12
までを実行してください.
平方根を求める関数sqrt
は数学関数ライブラリにあります.
浮動小数点型計算における丸め誤差も実感してください.
演算の優先順位と結合法則
演算の優先順位が
,
教科書p. 205
に書いてあります.
数学での,
和と積の優先順位のようなものが,
他の 様々な演算に対して, C
でどのように決まっているかの規則です.
ただし
,
以前から何度も述べていますが,
括弧を利用することにより,
この表を見なくても優先順位がわかる ようにプログラムは書きます.
この表は,
他の人が書いたプログラムを読む際には必要になることもあります.
このような表を利用してコンパクトなプログラムを書くことが好まれた時代が,
過去にあったからです.
自分 のプログラムでは,
この表に頼らなくても動作がわかるように書くとともに,
過去のプログラムで,
優先順位が わからない時には,
この表を利用するというのが,
正しい使い方です.
演算の結合性については
,
右結合の部分だけは,
注意してください.
特に,
式は値を持ち,
その値は左辺値である.
を利用したプログラムが多くあるからです
.
ライブラリ関数のリンクについて
何もオプションなしのコンパイルでは
,
「標準C
ライブラリ(/usr/lib/libc.a)
」だけがリンクされます.
なぜ数学関数ライブラリがリンクされないかというのは, C
の開発時期に関係があります.
当時は, 2
次記憶装 置もあまり容量がなかったのです.
実行可能ファイルに全てのライブラリ関数をリンクすると,
実行可能ファ イルのファイルサイズが大きくなりすぎるのです.
したがって,
特に必要としない限り,
標準ライブラリだけを リンクするようにして,
ファイルサイズの肥大化を防いだのです.
その後
,
共有ライブラリの仕組みが開発され,
ライブラリ関数はその呼び出しを記述しておけば,
システムに あるライブラリ関数を動的に呼び出すようになりました.
現在では,
特に指定をしない限り,
ライブラリのリン クは共有ライブラリを使うようになります.
ただし
,
システム起動時に実行するコマンド(
例えば,
スクリプトを利用して色々な設定をするshell
など)
では,
共有ライブラリを使えない可能性もあるので,
必要なライブラリをリンクした実行ファイルを作ること もできます.
このようなリンクを「静的リンク」と言います.
レポート問題
•
教科書p. 201, List 7-10
で,
原点と(1.0e160, 1.0e160)
との距離を求めるとどのような結果になるか? (
下の注意も読む.)
件名: overflow
•
上 の よ う な 場 合 で もoverflow
を 起 こ さ ず に 動 作 す る よ う に,
プ ロ グ ラ ム を 書 き 直 せ.
た だ し, long double
を用いないで, double
型を使うこと(
下の注意も読む).
件名: List7-10.c
• Wikipedia, https://ja.wikipedia.org/wiki/IEEE_754
に, − 118.625
のfloat
型の2
進表記が書 かれているが,
この講義での処理系ではどうなっているか? − 118.625
のfloat
型の2
進表記を出力す るプログラムを書け.
件名: IEEE-754.c
注意
平面上の原点からの距離を計算する関数として
, hypot
という関数が数学関数ライブラリにあります.
この 関数を利用すると,
上のレポート問題のようなエラーは起こりません.
ただし,
上のレポート問題では, hypot
を使わないでください.
整数型計算でも浮動小数点数計算でも