数値の精度
コンピュータによる数値計算における精度のこと。
浮動小数点のことなどあり、計算結果に誤差が出る話し。Mathematicaを用いて計算していたところ、任意精度という概念を採用していることはこちらに書いた。Mathematicaはを『1を3等分したもの』という形で情報を持ち続けることができて、これを絶対精度と呼んでいる。
今、生起確率についての絶対精度を考える。正確確率検定においては、この生起確率の大小比較を行い、等しいもの同士は、あくまでも等しいものとして扱いたい。生起確率は、非負の整数で表現された式であるが、割り算が入っているので、下手な順番でやると、精度の影響を受けて、本当は等しいもの同士に異なる値を算出してしまう。
これの絶対精度を保持し、しかも、等しいかどうかを比較するためには、次のように考える。分子と分母はそれぞれ、整数の掛け算に過ぎないから、掛け算だけを済ませてやって、分子と分母にひとつの整数を求めて、それらを比較する、もしくは、その商を比較する。
値が小さいときは可能だが、すぐに積の算出の段階で破綻する。
では、分子と分母の掛け算の要素を比べるというのも手。しかし、これは、というのが単純で
はのみで確定できることを利用していないので少しもったいない。
そこまで考慮するとが、浮動小数点の影響を受けるとはいえ、個々のの計算について、固定した計算関数を用いて、四則演算の順序を固定しておき、さらにの順も決めておけば、うまく行く。逆に言うと、これをうまくやらないと、正確確率検定の計算は、計算順序の影響を受けて『非常に』不正確になる。
この計算順序をそろえた「生起確率計算関数」はこちら
public static double lnprSortAnySize(int[][] d,double[] s){ //doubl[] s は s[k]=ln(k!)なるリスト int[] mcol2=new int[d[0].length]; int[] mlin2=new int[d.length]; int[] tmpsix2=new int[d[0].length*d.length]; int counter=0; int sum=0; for(int i=0;i<d.length;i++){ for(int j=0;j<d[i].length;j++){ mcol2[j]+=d[i][j]; mlin2[i]+=d[i][j]; sum+=d[i][j]; tmpsix2[counter]=d[i][j]; counter++; } } MiscUtil.sort(mcol2);//MiscUtil.sort関数は適当なソートのための関数 MiscUtil.sort(mlin2); MiscUtil.sort(tmpsix2); double lnpr=0; for(int i=0;i<mcol2.length;i++){ lnpr+=s[mcol2[i]]; } for(int i=0;i<mlin2.length;i++){ lnpr+=s[mlin2[i]]; } lnpr-=s[sum]; for(int i=0;i<tmpsix2.length;i++){ lnpr-=s[tmpsix2[i]]; } return lnpr; }