2012-04-15 21 views
13

El título es bastante autoexplicativo, la entrada tiene doble valor y quiero agregar/sustraer la menor cantidad posible.Cómo encontrar el valor doble siguiente/anterior más próximo (numeric_limits :: épsilon para el número dado)

+0

Would 'doble lado = valor + std :: :: numeric_limits épsilon() work'? ¿O me estoy perdiendo algo? – rve

+2

@rve: En algún punto que deja de aumentar el valor (no tiene ningún efecto), porque el valor con el que comenzó es una mejor aproximación del nuevo valor, que no se puede almacenar con precisión. Entonces te quedas atascado en un ciclo de no llegar del siguiente número. – GManNickG

+0

@rve, no, ya que es épsilon para el doble con valor 1, el épsilon se hace más y más grande con números más altos, vea http://en.wikipedia.org/wiki/Double-precision_floating-point_format – kovarex

Respuesta

19

Si su compilador implementa funciones matemáticas de C99/C++ 11, se puede utilizar el nextafter:

#include <cfloat> // DBL_MAX 
#include <cmath> // std::nextafter 

double x = 0.1; 

// next representable number after x in the direction of DBL_MAX 
double xPlusSmallest = std::nextafter(x, DBL_MAX); 

Incluso si su compilador no lo soporta, probablemente tiene un intrínseco para eso. (MSVC ha tenido _nextafter desde el año 2005, por ejemplo CCG probablemente lo implementa como estándar..)

Si el compilador no lo soporta, pero Boost está disponible para usted, usted puede hacer esto:

#include <boost/math/special_functions/next.hpp> // boost::float_next 

double x = 0.1; 

// next representable number after x 
double xPlusSmallest = boost::math::float_next(x); 

lo que equivale a esto (C99 emulando):

#include <boost/math/special_functions/next.hpp> // boost::nextafter 
#include <cfloat> // DBL_MAX 

double x = 0.1; 

// next representable number after x in the direction of DBL_MAX 
double xPlusSmallest = boost::math::nextafter(x, DBL_MAX); 

y si ninguno de los trabajos para usted, sólo tendrá que abrir una grieta en la cabecera Boost y copiarlo.

+0

Gracias por la buena respuesta, ya que ' m usando boost usaré su método. – kovarex

-4
#define FLT_MIN   1.175494351e-38F  /* min positive value */ 
#define FLT_MAX   3.402823466e+38F  /* max value */ 
#define DBL_MIN   2.2250738585072014e-308 /* min positive value */ 
#define DBL_MAX   1.7976931348623158e+308 /* max value */ 

http://xona.com/2006/07/26.html

+1

Creo que el OP quiere saber la diferencia * más pequeña posible * entre dos números flotantes/dobles, no los valores mínimos/máximos. –

+0

pero también muestra cómo los valores mínimos son menores que los almacenados en el archivo float.h –

+0

@AlexZ K. Luego depende de la FPU. El enlace que di muestra la precisión con la que FPU puede procesar. Y entonces siento que la diferencia mínima puede ser el valor positivo mínimo que se puede procesar –

7

Aquí hay un truco muy sucio que no es legal y solo funciona si su plataforma usa flotadores IEEE754: La representación binaria del flotador se ordena de la misma manera que el valor flotante, por lo que puede incrementar la representación binaria:

double x = 1.25; 

uint64_t * const p = reinterpret_cast<uint64_t*>(&x); 

++*p; // undefined behaviour! but it gets the next value 

// now x has the next value 

se puede lograr el mismo efecto totalmente contrario por hacer las habituales gimnasia copia binaria para obtener un valor adecuado uint64_t. Asegúrate también de verificar cero, infinito y NaN correctamente.

+0

He oído que GCC incluso reemplazará 'memcpy' entre tipos en aliasing cuando sea posible, aunque eso puede ser solo un mito. – GManNickG

+0

¿Esto manejará correctamente el desbordamiento de mantisa? ¿Qué sucede si la representación binaria es .111111111 * 2^k? ¿Da 0.00000000 * 2^{k + 1}? –

+0

@Alexandre C: Sí, lo hace. – user763305

-2

¿Qué tal:

x += fabs(x) * std::numeric_limits<double>::epsilon(); 
+0

¿Multiplicar por tipo? – GManNickG

+0

Supongamos que quiere agregar ':: min()', esto no funcionará para los números desnormalizados, y necesita una prueba para el caso regular. ¿Qué garantiza IEEE 754 sobre los ULP en multiplicación y adición? Yo pensaría que los números '1.5 * 2^n ≤ x <2^n + 1' redondearían hasta el doble del épsilon deseado después de la multiplicación, aunque debería funcionar con un fusionado multiple-add. – Potatoswatter

+0

Whoops - simplemente me olvidé de escribir épsilon ... corregido ahora –

Cuestiones relacionadas