2012-04-15 2 views
13

Der Titel ist ziemlich selbsterklärend, die Eingabe hat einen doppelten Wert, und ich möchte die kleinste mögliche Zahl hinzufügen/subtrahieren.So finden Sie den nächsten nächsten/vorherigen doppelten Wert (numeric_limits :: epsilon für eine gegebene Zahl)

+0

Würde 'Doppel next = Wert + std :: numeric_limits :: epsilon() Werk'? Oder fehlt mir etwas? – rve

+2

@rve: Irgendwann hört die Erhöhung des Wertes auf (hat keine Auswirkung), weil der Wert, mit dem Sie begonnen haben, eine bessere Annäherung an den neuen Wert ist, der nicht genau gespeichert werden kann. Sie bleiben also in einer Schleife stecken und erreichen die nächste Nummer nicht ganz. – GManNickG

+0

@rve, nein, wie es ist Epsilon für Doppel mit Wert 1, das Epsilon wird größer und größer mit höheren Zahlen, siehe http://en.wikipedia.org/wiki/Double-precision_floating-point_format – kovarex

Antwort

19

Wenn Ihr Compiler implementiert C99 die mathematischen Funktionen/C++ 11, können Sie mit dem 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); 

Selbst wenn Ihr Compiler unterstützt es nicht, ist es wahrscheinlich hat eine Instrinsic dafür. (MSVC hat zum Beispiel _nextafter seit 2005 hatte GCC wahrscheinlich implementiert es als Standard..)

Wenn Ihr Compiler nicht unterstützt, aber Boost ist Ihnen zur Verfügung, Sie können dies tun:

#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); 

welche dieser (emuliert C99) entspricht:

#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); 

und wenn keiner der Arbeit für Sie, werden Sie nur offen, um den Boost-Header knacken müssen und es kopieren.

+0

Vielen Dank für die nette Antwort, da ich ' m mit Boost verwende ich es Methode. – 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

Ich denke, das OP will die kleinste * Differenz * zwischen zwei Float/Double-Zahlen zu kennen, nicht die Min/Max-Werte. –

+0

aber es zeigt auch, wie die minimalen Werte sind kleiner als die in float.h Datei –

+0

@AlexZ K gespeicherten gespeichert. Dann hängt es von der FPU. Der Link, den ich gab, zeigt die Präzision, mit der FPU arbeiten kann. Und so fühle ich, dass die minimale Differenz der minimale positive Wert sein kann, der verarbeitet werden kann –

7

Hier ist ein sehr schmutziger Trick, der nicht wirklich legal ist und nur funktioniert, wenn Ihre Plattform IEEE754-Floats verwendet: Die binäre Darstellung des Floats ist auf die gleiche Weise wie der Float-Wert angeordnet, sodass Sie die binäre Darstellung erhöhen können:

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 

Sie können den gleichen Effekt ganz legal erreichen, indem er die üblichen Binärkopie turnen einen richtigen uint64_t Wert zu erhalten. Stellen Sie sicher, dass Sie auch auf Null, Unendlich und NaN prüfen.

+0

Ich habe gehört, dass GCC sogar "memcpy" zwischen Typen in Aliasing ersetzen wird, wenn es möglich ist, obwohl das nur ein Mythos sein kann. – GManNickG

+0

Wird das Mantissenüberlauf korrekt behandeln? Was passiert, wenn die Binärdarstellung .111111111 * 2^k ist? Gibt es .00000000 * 2^{k + 1}? –

+0

@Alexandre C: Ja, tut es. – user763305

-2

Wie wäre:

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

Multiplikation mit einem Typ? – GManNickG

+0

Angenommen, Sie wollten '' min() 'hinzufügen, funktioniert dies nicht für denormalisierte Zahlen und benötigt einen Beweis für den regulären Fall. Was garantiert IEEE 754 für ULPs unter Multiplikation und Addition? Ich würde denken, dass die Zahlen 1,5 * 2^n ≤ x <2^n + 1 'sich nach der Multiplikation auf das Doppelte des gewünschten Epsilons runden würden, obwohl es mit einem fusionierten Multiply-Add funktionieren sollte. – Potatoswatter

+0

Whoops - habe einfach vergessen, Epsilon zu schreiben ... jetzt behoben –