アプリ版:「スタンプのみでお礼する」機能のリリースについて

ある数値の累乗を求める(5の5乗など)プログラムを再帰関数・pow関数それぞれを使って作ったのですが、15の15乗からpow関数の結果に誤差が生じてしまいました。
知人からメモリが関係していると聞き、ネットで調べたのですが、理解できませんでした。
もしよろしければ詳しく教えていただけませんか。
よろしくお願いします。

A 回答 (2件)

メモリ?



倍精度浮動小数点は以下の構成になっています。
(-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に持ってきた瞬間に誤差が出ます。

※ 途中数値間違っていたらごめんなさい
    • good
    • 0

有効桁数などで検索して下さい。



double 型でだいたい 15桁くらいまでしか表現できなかったはずです。

15^15 = 437893890380859375

かな?
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!