- ベストアンサー
doubleで表現できる最も小さな値
たとえば double num = 1.0; このnumよりも大きなdoubleで表現できる最も小さな値を生成したいと考えています。 FLT_MINを単純に足してもnum==num+FLT_MINとなってしまいます。 num != num2となるような最小値の作りかたを教えて下さい
- みんなの回答 (8)
- 専門家の回答
質問者が選んだベストアンサー
No.3です。 回答の中に、実はヒントがあったのですが……。 さて、IEEE 754の形で表すとき、仮数部は2進数で52桁(+先頭に 1 を仮定)です。 だから、1.0 に影響を与える絶対値の最も小さい数値は、2進数で52桁目にある、2^(-52) です。 言い換えると、 1.(0 が 52個)に影響を与えるためには、0.(0 が 51個)1 が最小になります。 これが、2進数で、 1.1111111 を超えて 10.00000 (実際には指数部がひとつかわるけど)つまり、2.0 になるまで続きます。 ということで、(以下、表記は 10進数) 1.0 以上 2.0 未満 刻みは DBL_EPSILON 2.0 以上 4.0 未満 刻みは DBL_EPSILON * 2 4.0 以上 8.0 未満 刻みは DBL_EPSILON * 4 となります。 一般化すれば、 2^n 以上 2^(n + 1) 未満 で、刻みは DBL_EPSILON * 2 ^ n です。 (n < 0 でも同じ)
その他の回答 (7)
- qwertfk
- ベストアンサー率67% (55/81)
浮動小数の仕様を考えると、正の場合は double get_next(double d) { double next_d = d; unsigned long long& l = (unsigned long long&)next_d; if( l & 0xfffffffffffff == 0xfffffffffffff ) { l = l - 0xfffffffffffff; l += 0x10000000000000; } else { l += 1; } return next_d; } でいけるんじゃないかと思います。 基本的には仮数部*2^nという構造になっており、仮数部は1.0~1.9999...なので 二つの数を比較するときに、まず指数部が一致していなければ指数部が大きいほうが大きい値、 そうでなければ仮数部の大きいほうが大きい値、となっているはずなので。
- akayoroshi
- ベストアンサー率50% (46/91)
> ある数値の次の数値 C99のnextafter関数
- asuncion
- ベストアンサー率33% (2127/6289)
>このnum(直前に出てきた1.0のことですよね?)よりも大きなdoubleで表現できる最も小さな値を生成したい この文の意味がどうしてもわかりません。 どなたか解説をお願いできないでしょうか。
- samtomsan
- ベストアンサー率55% (1060/1897)
ANo.2です。 忘れていました。 FLT_MINはfloatですから、doubleの場合はDBL_MINですね。 http://simd.jugem.jp/?eid=18 下記も参考になると思います。 http://www.cc.kyoto-su.ac.jp/~yamada/programming/float.html
- 麻野 なぎ(@AsanoNagi)
- ベストアンサー率45% (763/1670)
すでに回答がありますが、このような数値は、DBL_EPSILON と定義されています。 手元のコンパイラ(のヘッダファイル)を調べると、具体的には、2.2204460492503131E-16 という数値のようです。 さて、この数値はなんでしょうか? また、なぜ、num == num + DBL_MIN (double なら、FLT_MIN はそもそもおかしいでしょう)なのかという点です。 まず、現在多く使われている浮動小数点は、IEEE 754形式と呼ばれるものです。 これで、double を表すと、 符号 1 + 小数点以下52桁(ただし2進数で)*2 ^(指数) となります。 ※実際には、(指数)は、以下の説明とは具体的な数値はちょっと違います。 ※あと、ここで使っている ^ はべき乗の意味とします(この説明では、ビット演算子ではありません) さて、実は、DBL_EPSILON (2.2204460492503131E-16) は、2倍して、2倍して……と、52回繰り返すと、ぴったり1になる数値です。 言い換えると、2^(-52) に相当する数値です。 1.0 = (1 + 小数点以下は、0 )* 2^0 であることを考えると、IEEE 754 で表すと 1.0 = (1 + 小数点以下である52個の0)* 2 ^ 0 になります。 (ただし表記は2進数) これに何かを足して、1.0 じゃないものにしようと思えば、小数点以下にならんだ52個の0を変化させなければいけません。 つまり、0.(51個の0)1 (ただし表記は2進数)が最小の数値です。 10進数では 1.0/10 = 0.1, 0.1/10 = 0.01, 0.01/10 = 0.001 と、10で割るごとに桁がひとつ下がってゆきます。 同じように2進数では 1.0/2 = 0.1, 0.1/2 = 0.01, 0.01/2 = 0.001 と2で割るごとに桁がひとつ下がってゆきます。(ただし表記は2進数) つまり、2進数表示で、 0.(51個の0)1 という数値は、2で割ることを52回繰り返した数字になります。 これが、DBL_EPSILON = 2.2204460492503131E-16 = 2^(-52) という意味です。 一方で、DBL_MIN (2.2250738585072014E-308)は、1.0 からみると2進数表記で小数点以下 1024桁の数値になります。 数値を表すのに、たかだか 2進52桁しかないのに、1024桁も小さい数値を足しても、結果は変わらないということになります。
- samtomsan
- ベストアンサー率55% (1060/1897)
パソコンの場合の数値表現はIEEE754ですから、下記のIEEE754倍精度の場合の説明を見れば判るかと思います。 http://d.hatena.ne.jp/lemniscus/20090816/1250441897
- επιστημη(@episteme)
- ベストアンサー率46% (546/1184)
補足
分かりにくい質問になってしまい申し訳ありません。 どうやら先に回答いただいたDBL_EPSILONで問題は解決しそうですが 本来の意図とは異なっています。 本来の質問のイメージは double型は8バイトなので(2^8)^8個(パターン)の数が表現できます。 実際はNaNなどがあるのでそれよりも少なくなると思いますが。 この数列を昇順にソートしたときの ある数値の次の数値が知りたいのです。 doubleの刻み幅は常にDBL_EPSILONではないようなので厄介なのです もう少し回答を募ってみようと思います。