数値の精度

コンピュータによる数値計算における精度のこと。
浮動小数点のことなどあり、計算結果に誤差が出る話し。Mathematicaを用いて計算していたところ、任意精度という概念を採用していることはこちらに書いた。Mathematica\frac{1}{3}を『1を3等分したもの』という形で情報を持ち続けることができて、これを絶対精度と呼んでいる。
今、生起確率Pr=\frac{\prod (n_{i.})!\times \prod (n_{.j})!}{n_{..}!\prod_{all_cells} n_{ij}!}についての絶対精度を考える。正確確率検定においては、この生起確率の大小比較を行い、等しいもの同士は、あくまでも等しいものとして扱いたい。生起確率は、非負の整数で表現された式であるが、割り算が入っているので、下手な順番でやると、精度の影響を受けて、本当は等しいもの同士に異なる値を算出してしまう。

これの絶対精度を保持し、しかも、等しいかどうかを比較するためには、次のように考える。分子と分母はそれぞれ、整数の掛け算に過ぎないから、掛け算だけを済ませてやって、分子と分母にひとつの整数を求めて、それらを比較する、もしくは、その商を比較する。
値が小さいときは可能だが、すぐに積の算出の段階で破綻する。
では、分子と分母の掛け算の要素を比べるというのも手。しかし、これは、k!というのが単純で
\prod k_i!\{k_i\}のみで確定できることを利用していないので少しもったいない。
そこまで考慮すると\sum ln(k_i!)が、浮動小数点の影響を受けるとはいえ、個々のln(k_i)!の計算について、固定した計算関数を用いて、四則演算の順序を固定しておき、さらに\sum ln(k_i)!の順も決めておけば、うまく行く。逆に言うと、これをうまくやらないと、正確確率検定の計算は、計算順序の影響を受けて『非常に』不正確になる。
この計算順序をそろえた「生起確率計算関数」はこちら

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;
		
	}