SQLインジェクション対策はおすみですか?
開発開始時点からのコンサルティングから、公開済みWebサイトの脆弱性検査、
脆弱性発見後の適切な対策まで
トップ «前の日記(2007-05-29) 最新 次の日記(2007-06-01)» 編集
過去の日記

2007-05-31 恐ろしい毒

IEEE754のとりうる整数の範囲

hnwさんの日記は一見すると平易だが、恐ろしい毒がこっそり忍ばせてある。読者は表向きの平易に書かれたウンチクを楽しみながら、裏の毒を味わうという二重の楽しみを体験することができる。

今日はPHPのround関数に関して前回と違った切り口で紹介してみます。また、コンピュータ上での整数についても少し紹介してみます。

前回の記事「PHPの奇妙なround関数」(id:hnw:20070515)を読んで、小数点が付いた数なんてPHPで触ったことないから関係ないや、なんて考えた方が居るかもしれません。そんな方のために、今回は整数を四捨五入してみます。

[hnwの日記 - round関数で整数を四捨五入してみるより引用]

今回の毒は、以下の部分だ。

そして、IEEE64bit浮動小数点数であれば仮数部が52bitありますので、-2の53乗から2の53乗(約9000兆)までの整数は全て正確に表現できます。つまり、今回登場した変数値はどれも見た目通りの整数です*1。

仮数部が52bitあると、どうして2の53乗までの整数が表現できるのか、それを理解するためには、2進浮動小数点数の内部表現についての理解が必要となる。

一般に、2進浮動小数点数は、以下のような内部表現をとる。

± 1.bbbbbbbbbbbb × 2^nnn

1.bbbの部分が仮数部である。仮数部の最上位桁が1固定になっている理由は正規化をしているためである。そして、最上位桁が1と決まってるからには、わざわざメモリ上の1ビットを割り当てる必要がないことから、現実のメモリ上の表現としては省略している。これをケチ表現(economized form)と呼ぶ。すなわち、IEEE754形式の浮動小数点数は、実際には仮数部は53bitあるわけだ。
ここで、仮数部が全て1となる数を検討してみよう。

1.111 ..... × 2^52 = 2^53 - 1

であるので、2^53 - 1までは表現できることがまず分かる。
この数に1を足すと、有効桁数としては54ビットとなるわけだが、末尾が0であるので、

1.0 × 2^53

として正しく表現できる。この数に1を足すと、有効桁数が足らないので表現できない。すなわち、2^53が正確に表現できる整数の上限となる。

このようにして、1 〜 2^53 までは表現できることがわかる。
負の数字については、符号ビットにより対応する。
ゼロについては、浮動小数点数の場合、特別扱いする必要があるのだが、IEEE754の場合は、前に述べた非正規化数の特別な場合(仮数部が全て0)として表現する。

符号なし2進52ビット固定小数点数の場合は、0 〜 2^52 - 1 の範囲の整数を表現できるわけであるが、IEEE754は仮数部のケチ表現などにより見かけの有効数字を桁増しして、2^53までの数値を正確に表現できる。巧妙な手法である。

このように複雑な内容を、hnw氏はサラリと書き流し、読者がワナに掛かるのを待っているのである。
まことに恐ろしい毒と言わざるを得ない。

本日のツッコミ(全1件) [ツッコミを入れる]
hnw (2007-06-01 11:20)

お褒め頂いてありがとうございます。僕自身「doubleで表現できない最小の自然数は2^53+1である」ということに最近気づいたんですが、単体で記事を書く内容でもないかなと思ってストックしておいたんですね。今回それを絡めた記事を書いてみたわけなんですが、徳丸さんをはじめ知識のある方ほど「2^53までというのは中途半端だ」という違和感を持つようで、なかなか面白いものです。

そんなわけで、わざわざワナを潜ませているつもりはありません。むしろ、僕が本当に書きたかった内容がバレバレということかもしれませんね。

本日のリンク元
アンテナ
その他のリンク元
検索

SQLインジェクション対策はおすみですか?
開発開始時点からのコンサルティングから、公開済みWebサイトの脆弱性検査、
脆弱性発見後の適切な対策まで
トップ «前の日記(2007-05-29) 最新 次の日記(2007-06-01)» 編集