暗号化のための変換の応用2(作成中)
update: 9/08/2008
暗号理論の応用を試みた行列変換のあれこれ。そのレポートの続きです。
Contents
◎ 逆行列変換フローチャート
掃出し法のアルゴリズムはエラー要因を良く考慮したものがありますが、
改めて作成してみるとプログラム言語の影響と思われる部分もありました。
[アスキーデータの行列化]
|
[ det = 0 ] --- yes --- [ (a) 他の変換 ]
|
[ 掃出し法 A → A-1 ]
|
[ 小数点 n 桁での打切り B = A-1 - ε(n+1) ]
|
[ ファイルに保存 ]
|
[ ファイルから読出し ]
|
[ 掃出し法 B → B-1 ]
|
[ 復元精度の比較 B-1 = A ? ] --- no --- [ (b) 他の変換 ]
|
[ 小数点桁 n の利用 ]
top
◎ 3x3行列の場合
3x3 行列での実験プログラムでは、nと復元失敗の関係は次のようになりました。
英数文字629=? の組合せからランダム抽出で1000回を10セット試験します。
保存桁n / セット | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 割合 |
4 | 711 | 684 | 689 | 666 | 694 | 715 | 687 | 708 | 710 | 696 | 70% |
5 | 1 | 2 | 1 | 1 | 1 | 3 | 0 | 3 | 2 | 4 | - 0.4% |
6 | 0 | 2 | 0 | 1 | 2 | 2 | 0 | 3 | 1 | 2 | - 0.3% |
7 | 1 | 2 | 0 | 1 | 0 | 1 | 3 | 5 | 2 | 1 | - 0.5% |
計算のように4桁ではありませんが、5桁からはほぼ完全に復元できました。
保存桁を増やしても精度が改善されないのは、復元行列を整数へ
近似する時にエラーが起きてたのが原因でした。
例えば復元の結果 65.000123 という値になったのに、整数変換して整数 65 と
比較一致すると False 判定がでます。
整数値の比較方法としては、次のものが考えられます。
@ 四捨五入の方法
a) Int 型でのキャスト。(int)1.99 = 1.0 のように切下げになるのを利用する。
b) Java には、最も近い整数に変換する Math.rint(double) が
用意されているので、これを使う。
A 極限値の考え方
2数の差の絶対値により評価します。Math.abs(a-b)<= 0.00001 のような判定です。
@の方法が当初のプログラムでしたが、Aの方法に変更しました。
整数値への四捨五入ですので、差が 0.5 以上の場合、復元失敗と見なします。
保存桁n / セット | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 割合 |
4 | 717 | 704 | 702 | 701 | 707 | 696 | 701 | 698 | 663 | 698 | 70% |
5 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | - 0.01% |
6 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | - 0.01% |
なぜ@の方法では駄目なのでしょう? Math.rint() メソッドにエラーが無いならば、
A==B の数値判定では、初期化後に代入した数値と、演算後に代入した数値では
ビット的な差がでる場合があるのかもしれません。
Aの方法でも残るエラーは、教科書通りにピボットがゼロとなる例でした。
2桁以上の例はあまり見かけないので記録しておきました。
98 101 75 80 112 117
98 101 79 85 119 67
76 101 112 52 115 82
2行目と3行目を交換すると、無事に計算できますが、交換行の記録が必要になり、
0.01% ほどなので、この場合は逆行列変換は中止しました。
top
◎ 2x2行列の場合
3x3行列で思わぬエラーが出たので、2X2行列も丁寧に調査しました。
保存桁n / セット | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 割合 |
3 | 974 | 974 | 970 | 975 | 978 | 964 | 969 | 969 | 983 | 978 | 97% |
4 | 399 | 391 | 366 | 403 | 421 | 384 | 382 | 383 | 401 | 435 | 40% |
5 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0.002% (5回に1回ぐらい) |
6 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0.002% (5回に1回ぐらい) |
計算と異なり、5桁までの保存が必要でした。
0.002% のエラーの原因は特殊な場合に起きるゼロ計算エラーでした。
次の行列式はいずれもゼロですが、double 型の関数呼出で計算した値は
大きな負の値になっていました。
double det=det2(a,b,c,d);
...
public static double det2(double a, double b, double c, double d){
double detr=a*d-b*c;
return detr;
}
70 76 87 120
105 114 → det = -6.36804E7 87 120 → det = -9.43035E7
念のため、50 〜 120 の値で行列式を計算すると、
50x50 - 50x50 = -6.25E6
120x120 - 120x120 = -2.0736E8
のように変化していきます。1を足すと、-6249999 のようになるので、
プログラムとしては、負の数として認識しています。
関数呼出でも引き算ではこのような現象は起きず、関数呼出せずに、
ベタで書いても( double det=a*d-b*c ; ) このような計算エラーは起きませんでした。
論理演算での符号ビット、補数表現などが関係していそうですが、
エラーメッセージがあってもよさそうです。
top
◎ 4x4〜10x10行列の場合
4x4
保存桁n / セット | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 割合 |
4 | 883 | 885 | 896 | 868 | 901 | 894 | 886 | 870 | 868 | 877 | 88% |
5 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0.005% (2回に1回ぐらい) |
5x5
保存桁n / セット | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 割合 |
4 | 982 | 976 | 969 | 967 | 967 | 965 | 964 | 967 | 958 | 965 | 97% |
5 | 0 | 3 | 1 | 1 | 1 | 1 | 0 | 1 | 0 | 1 | 0.1 - 0.3% |
6 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0.002% (5回に1回ぐらい) |
7x7
保存桁n / セット | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 割合 |
4 | 1000 | 998 | 996 | 998 | 998 | 995 | 997 | 992 | 995 | 998 | 99% |
5 | 19 | 20 | 23 | 26 | 21 | 26 | 30 | 17 | 17 | 26 | - 0.6% (10回に3回ぐらい) |
6 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0.01% |
10x10
保存桁n / セット | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 割合 |
4 | 996 | 997 | 997 | 995 | 999 | 998 | 995 | 998 | 999 | 998 | 99% |
5 | 146 | 166 | 144 | 158 | 144 | 148 | 158 | 166 | 176 | 150 | 15% |
6 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0.005% (2回に1回ぐらい) |
最後まで残ったエラーは、やはり掃出し法のピボットがゼロとなるケースでした。
105 115 66 108
57 106 102 77
53 106 106 112
54 57 56 86
89 55 90 53 121
89 55 88 86 72
74 48 76 107 121
113 66 49 78 120
84 57 121 50 70
107 116 119 74 106 86 78
107 116 102 109 115 88 81
88 52 99 50 116 119 70
118 78 76 88 68 54 100
55 67 84 118 89 84 108
104 99 50 57 83 69 99
87 102 102 106 73 122 78
50 55 74 109 71 86 53 54 99 68
100 110 55 100 120 81 98 116 84 122
108 103 100 89 66 109 104 114 66 51
98 78 65 112 51 84 102 71 80 80
82 103 113 121 71 87 105 69 57 67
53 118 80 50 70 74 113 112 87 104
107 87 98 66 55 67 51 55 107 121
103 78 78 121 70 122 54 121 69 53
71 110 68 52 80 78 109 107 87 122
68 113 57 75 74 77 117 76 106 54
top
◎ 結論
行列次元 | 安全な保存小数点桁数 | 復元失敗の確率 % | 保存容量の増加(byte) |
2x2 | 5 | 0.002 | 16 → 64 |
3x3 | 5 | 0.01 | 36 → 126 |
4x4 | 5 | 0.005 | 64 → 224 |
5x5 | 5 | 0.002 | 100 → 350 |
7x7 | 6 | 0.01 | 196 → 686 |
10x10 | 6 | 0.005 | 400 → 5600 |
文字数はn2で、1文字を2桁の数字と考えると Unicode では4byteです。
よって当初の 4n2 から、5桁の場合は14n2で 3.5倍、
6桁の場合は16n2で4倍ぐらいの保存容量の増加があります。
top
◎ サンプルプログラム
ダウンロード ( Java )
top
◎ 改良結果
実装中...
top
調査レポート作成 :tmlbworks