FLT_MIN
ゼロに最も近い定数があります。some number
価値に最も近づく方法は?
例として:
float nearest_to_1000 = 1000.0f + epsilon;
// epsilon must be the smallest value satisfying condition:
// nearest_to_1000 > 1000.0f
特殊関数を使わずに数式を使いたいです。
FLT_MIN
ゼロに最も近い定数があります。some number
価値に最も近づく方法は?
例として:
float nearest_to_1000 = 1000.0f + epsilon;
// epsilon must be the smallest value satisfying condition:
// nearest_to_1000 > 1000.0f
特殊関数を使わずに数式を使いたいです。
Cは、<math.h>
ヘッダーでこのための関数を提供します。は、に向かう方向の、nextafterf(x, INFINITY)
の次の表現可能な値です。x
INFINITY
ただし、自分でやりたい場合は、次のようにします。
以下は、IEEE 754を想定した、単精度(浮動小数点)の場合に求めるイプシロンを返します。ライブラリルーチンの使用については、下部の注を参照してください。
#include <float.h>
#include <math.h>
/* Return the ULP of q.
This was inspired by Algorithm 3.5 in Siegfried M. Rump, Takeshi Ogita, and
Shin'ichi Oishi, "Accurate Floating-Point Summation", _Technical Report
05.12_, Faculty for Information and Communication Sciences, Hamburg
University of Technology, November 13, 2005.
*/
float ULP(float q)
{
// SmallestPositive is the smallest positive floating-point number.
static const float SmallestPositive = FLT_EPSILON * FLT_MIN;
/* Scale is .75 ULP, so multiplying it by any significand in [1, 2) yields
something in [.75 ULP, 1.5 ULP) (even with rounding).
*/
static const float Scale = 0.75f * FLT_EPSILON;
q = fabsf(q);
/* In fmaf(q, -Scale, q), we subtract q*Scale from q, and q*Scale is
something more than .5 ULP but less than 1.5 ULP. That must produce q
- 1 ULP. Then we subtract that from q, so we get 1 ULP.
The significand 1 is of particular interest. We subtract .75 ULP from
q, which is midway between the greatest two floating-point numbers less
than q. Since we round to even, the lesser one is selected, which is
less than q by 1 ULP of q, although 2 ULP of itself.
*/
return fmaxf(SmallestPositive, q - fmaf(q, -Scale, q));
}
以下は、渡された値の後にfloatで表現可能な次の値を返します(-0と+0を同じものとして扱います)。
#include <float.h>
#include <math.h>
/* Return the next floating-point value after the finite value q.
This was inspired by Algorithm 3.5 in Siegfried M. Rump, Takeshi Ogita, and
Shin'ichi Oishi, "Accurate Floating-Point Summation", _Technical Report
05.12_, Faculty for Information and Communication Sciences, Hamburg
University of Technology, November 13, 2005.
*/
float NextAfterf(float q)
{
/* Scale is .625 ULP, so multiplying it by any significand in [1, 2)
yields something in [.625 ULP, 1.25 ULP].
*/
static const float Scale = 0.625f * FLT_EPSILON;
/* Either of the following may be used, according to preference and
performance characteristics. In either case, use a fused multiply-add
(fmaf) to add to q a number that is in [.625 ULP, 1.25 ULP]. When this
is rounded to the floating-point format, it must produce the next
number after q.
*/
#if 0
// SmallestPositive is the smallest positive floating-point number.
static const float SmallestPositive = FLT_EPSILON * FLT_MIN;
if (fabsf(q) < 2*FLT_MIN)
return q + SmallestPositive;
return fmaf(fabsf(q), Scale, q);
#else
return fmaf(fmaxf(fabsf(q), FLT_MIN), Scale, q);
#endif
}
ライブラリルーチンが使用されますが、fmaxf
(引数の最大値)とfabsf
(絶対値)は簡単に置き換えることができます。fmaf
multiply-addが融合されたアーキテクチャのハードウェア命令にコンパイルする必要があります。それができない場合fmaf(a, b, c)
、この使用法では。に置き換えることができます(double) a * b + c
。(IEEE-754 binary64には、置き換えるのに十分な範囲と精度がありfmaf
ます。他の選択肢はそうでdouble
はない場合があります。)
q * Scale
fused-multiply addの別の代替方法は、異常な場合にいくつかのテストを追加し、それらを個別に処理することです。*
その他の場合、乗算と加算は通常の演算子と演算子で別々に実行できます+
。