- 締切済み
数値の誤差
ある数値の累乗を求める(5の5乗など)プログラムを再帰関数・pow関数それぞれを使って作ったのですが、15の15乗からpow関数の結果に誤差が生じてしまいました。 知人からメモリが関係していると聞き、ネットで調べたのですが、理解できませんでした。 もしよろしければ詳しく教えていただけませんか。 よろしくお願いします。
- みんなの回答 (2)
- 専門家の回答
みんなの回答
- nuko_punch
- ベストアンサー率40% (10/25)
メモリ? 倍精度浮動小数点は以下の構成になっています。 (-1)^符号部 * 2^(指数部-1023) * (1.仮数部) 符号部:1[bit] 指数部:11[bits] 仮数部:52[bits] 計:64[bits] 例)[符号部,指数部,仮数部]で書きます 1.0は[0,1023,0000....0b] 0.5は[0,1022,0000....0b] 1.5は[0,1023,1000....0b] ○本題 15^15は 437,893,890,380,859,375 で二進数表記した場合 110 0001 0011 1011 0110 0010 1100 0101 1001 0111 0111 0000 0111 1110 1111b 式『(-1)^符号部 * 2^(指数部-1023) * (1.仮数部)』を当てはめると 下記になります。 (-1)^0 * 2^58 * 1.10 0001 0011 1011 0110 0010 1100 0101 1001 0111 0111 0000 0111 1110 1111b 符号部は素直に0 指数部は58 = (1081 - 1023) 仮数部は10 0001 0011 1011 0110 0010 1100 0101 1001 0111 0111 0000 0111 1110 1111b ここでちょっと見てください。 58[bits]では52[bits]を6[bits]超えています。 この場合、浮動小数点では影響の小さい(値の小さい)下位のビットを四捨五入します。 10 0001 0011 1011 0110 0010 1100 0101 1001 0111 0111 0000 0111 11(10 1111)b カッコ内が四捨五入対象(その中の最上位ビットが0or1) よって 仮数部は 10 0001 0011 1011 0110 0010 1100 0101 1001 0111 0111 0000 1000 00b となります。 これが誤差の原因です。 確かめ算をします。 [0,1081,1000010011101101100010110001011001011101110000100000b] は (-1)^0*2^(1081-1023)*(1.1000010011101101100010110001011001011101110000100000b) =2^58*(1.1000010011101101100010110001011001011101110000100000b) =2^6*2^52*(1.1000010011101101100010110001011001011101110000100000b) =2^6*11000010011101101100010110001011001011101110000100000b =11000010011101101100010110001011001011101110000100000000000b =437,893,890,380,859,392 IA-32アーキテクチャではサイズを大きくした、拡張倍精度浮動小数点などもありますが。 (x87 FPU命令ですが) 結局は破綻する箇所が先送りされるだけです。 拡張倍精度浮動小数点は、コンパイラ独自拡張や機械語でないと使用出来ません。 インラインアセンブラもOKですが。 Cのdoubleに持ってきた瞬間に誤差が出ます。 ※ 途中数値間違っていたらごめんなさい
- koko_u_
- ベストアンサー率18% (459/2509)
有効桁数などで検索して下さい。 double 型でだいたい 15桁くらいまでしか表現できなかったはずです。 15^15 = 437893890380859375 かな?