C ++ hat std::nextafter()
, was den nächsten darstellbaren Wert nach einem gegebenen Gleitkommawert f zurückgibt . In meinem Fall möchte ich n Bits Slop in den unteren Mantissenbits zulassen , sodass für 3 Bits Slop der 8. nächste Wert nach einem bestimmten Wert f erforderlich wäre . Ich könnte nextafter()
acht Mal anrufen , aber gibt es eine bessere Möglichkeit, damit umzugehen?
Bei den meisten Werten können Sie mit dem Umwandeln des FP-Werts in uint_64
, dem Hinzufügen der Toleranz ( 1<<3
für 3 Bit Slop) und dem anschließenden Umwandeln double
dank des Layouts von IEEE 754 auskommen. Dies basiert jedoch auf dem Gleitkomma von IEEE 754 ( eine gute Annahme, aber auch nicht ganz solide).
(Als Hintergrund möchte ich dies verwenden, um Schnittpunkte der Strahloberfläche zu heben, die sich aufgrund von FP-Ungenauigkeiten gelegentlich innerhalb der Oberfläche befinden. Diejenigen, die mit robustem Gleitkomma vertraut sind, werden verstehen, warum dies epsilon
eine schreckliche Lösung ist.)
quelle
std::numeric_limits<T>::is_iec559
, um zu überprüfen, ob IEEE 754 verwendet wird, und die Funktion entsprechend zu spezialisieren.Antworten:
Ein naiver Ansatz könnte darin bestehen, den Abstand zwischen einem Wert und dem nächsten darstellbaren Float mit 8 zu multiplizieren, anstatt 8 Mal aufzurufen
std::nextafter
Hier gibt es einige Tests, aber es liegt an Ihnen, festzustellen, ob dies für Ihren Anwendungsfall geeignet ist.
Bearbeiten
Wie von Steve Hollash bemerkt ,
x
kann das so groß sein, dassx + d == d
. Daniel Jour schlug vor,frexp
(undldexp
) zu nutzen, aber im folgenden Versuch werde ich einen anderen Ansatz verwenden, um die Richtung zu bestimmen.Beachten Sie, dass dies
std::numeric_limits<double>::has_infinity == true
ansonsten vorausgesetzt wird::lowest()
und::max()
verwendet werden muss.Das sind einige Ergebnisse
quelle
x+d
jedoch nicht das, wonach Sie suchen. Wenn x groß ist, dann ist (x + d) == x. Aber ich mag die Idee: Berechnen Sie den Wert, der dem Bit niedrigster Ordnung entspricht, mit einem übereinstimmenden Exponenten, der durch den "Slop" skaliert und dann zum ursprünglichen Wert addiert wird.nextafter
, wie man die "Richtung" passiert.frexp
davor undldexp
danach sollte funktionieren, nein?frexp
insbesondere kann ich Welten bewegen. Vielen Dank!Soweit ich weiß, gibt es dafür keine Standardfunktion. Boost hat Sie jedoch abgedeckt: Siehe
boost::math::float_advance
. Wenn Sie dies zum Vergleichen von zwei Floats verwenden, möchten Sie wahrscheinlichboost::math::float_distance
stattdessen.quelle