2009年1月23日金曜日

浮動小数点

ちょっと,浮動小数点の演算でハマっていた所があったのでメモがてら.

とある事情で,文字認識実験をしていました.その実験は,平仮名46文字を認識するというもので,認識手法の中に重み付きユークリッド距離というものがありました.重み付きユークリッド距離とは,

D(x, u) = √(∑(x[i]-u[i])^2/v[i])

x : 未知の文字の特徴ベクトル
u : ある字種の平均特徴ベクトル
v : uの分散ベクトル

というもので,適当にJavaで組んであるものを動かしていました.ところが,ある文字に対しては,非常に良い認識率が得られるが,ある文字は全く認識できない(認識率0%),という事態になってしまいました.
ファイルの読み込みや,計算式を入念にチェックしましたが,原因が見つかりませんでした.

よくよく考え,D(x, u)を出力してみました.

結果
NaN

ここでやっと原因が分かりました.単に0.0f/0.0fという演算が発生していたというだけのことです(上の式の場合x[i]-u[i]=0.0fかつ,v[i]=0.0fとなっていた).

そんなわけで,この問題は解決しましたが,浮動小数点における特殊な数について少しばかり調べてみました.上の実験では,Java,float型を使用してましたので,それに限りますが.
ちなみに,JDKのバージョンは1.6.0_06です.

Float.POSITIVE_INFINITY
正の無限大です.Floatクラスでの定義は,
public static final float POSITIVE_INFINITY = 1.0f / 0.0f;
でした.

Float.NEGATIVE_INFINITY
正の無限大です.Floatクラスでの定義は,
public static final float NEGATIVE_INFINITY = -1.0f / 0.0f;
でした.

Float.NaN
Not a Number(=非数)です.Floatクラスでの定義は,
public static final float NaN = 0.0f / 0.0f;

NaNの発生条件には以下のようなものがあります.

異符号の無限大同士の加算
同符号の無限大同士の減算
0と無限大の乗算
0同士の除算
無限大同士の除算
被除数が無限大の剰余
除数が0の剰余
負数の平方根
値が未定義となる逆三角関数,対数関数

また,この定数は特殊であり,
NaN op something (op -> "==", "<", ">", "<=", ">=")
は必ずfalseであり,
NaN != something
は必ずtrueとなります.

実際,あるfloat値がNaNかどうかを返すメソッドboolean isNaN(float)は以下のように定義されていました.

static public boolean isNaN(float v) {
return (v != v);
}

vがNaNの時にだけ,v != vはtrueとなります.

今日はこんなところで.

0 件のコメント: