c++ - nint - Verleiht ein int nach std:: floor das richtige Ergebnis?



c++ trunc (4)

Der Bereich von double ist viel größer als der Bereich von 32 oder 64 bit Ganzzahlen, weshalb std::floor ein double zurückgibt. Casting nach int sollte in Ordnung sein, solange es innerhalb des geeigneten Bereichs liegt - aber bedenken Sie, dass ein double nicht alle 64-Bit-Integer genau darstellen kann, sodass Sie auch Fehler bekommen, wenn Sie über den Punkt hinausgehen, bei dem die Genauigkeit von double ist so, dass der Unterschied zwischen zwei aufeinanderfolgenden Doppelpunkten größer als 1 ist.

https://src-bin.com

Ich hätte gern eine floor Funktion mit der Syntax

int floor(double x);

aber std::floor gibt ein double . Ist

static_cast <int> (std::floor(x));

Garantiert mir die korrekte Integerzahl, oder könnte ich ein off-by-one Problem haben? Es scheint zu funktionieren, aber ich würde es gerne wissen.

Für Bonuspunkte, warum zum Teufel macht std::floor ein double an erster Stelle?


Answer #1

Der C ++ Standard sagt (4.9.1):

"Ein rvalue eines Fließkommatyps kann in einen rvalue eines Integer-Typs konvertiert werden. Die Konvertierung wird abgebrochen, dh der Bruchteil wird verworfen. Das Verhalten ist nicht definiert, wenn der abgeschnittene Wert nicht im Zieltyp dargestellt werden kann".

Wenn Sie also ein double in ein int konvertieren, liegt die Zahl innerhalb des Bereichs von int und die erforderliche Aufrundung ist in Richtung null. Dann genügt es, die Zahl einfach in int zu konvertieren:

(int) x;


Answer #2

Wenn Sie mit verschiedenen numerischen Bedingungen umgehen und verschiedene Arten von Konvertierungen kontrolliert handhaben möchten, sollten Sie sich vielleicht Boost.NumericConversion . Diese Bibliothek ermöglicht es, seltsame Fälle (wie außerhalb des Bereichs, Rundungen, Bereiche usw.) zu behandeln.

Hier ist das Beispiel aus der Dokumentation:

#include <cassert>
#include <boost/numeric/conversion/converter.hpp>

int main() {

    typedef boost::numeric::converter<int,double> Double2Int ;

    int x = Double2Int::convert(2.0);
    assert ( x == 2 );

    int y = Double2Int()(3.14); // As a function object.
    assert ( y == 3 ) ; // The default rounding is trunc.

    try
    {
        double m = boost::numeric::bounds<double>::highest();
        int z = Double2Int::convert(m); // By default throws positive_overflow()
    }
    catch ( boost::numeric::positive_overflow const& )
    {
    }

    return 0;
}

Answer #3
static_cast <int> (std::floor(x));

macht ziemlich viel was du willst, ja. Es gibt Ihnen die nächste Ganzzahl, gerundet auf -infinity. Zumindest solange Ihre Eingabe in dem Bereich liegt, der durch Ints dargestellt werden kann. Ich bin nicht sicher, was Sie meinen, indem Sie .5 und so weiter hinzufügen, aber es wird nicht den gleichen Effekt haben

Und std :: floor gibt ein Double zurück, weil das das allgemeinste ist. Manchmal möchten Sie vielleicht ein Float oder Double abrunden, aber den Typ beibehalten. Das heißt, rund 1,3 f bis 1,0 f statt 1.

Das wäre schwer zu tun, wenn std :: floor einen int zurückgibt. (oder zumindest hat man eine extra unnötige Besetzung, die die Dinge verlangsamt).

Wenn floor nur die Rundung selbst ausführt, ohne den Typ zu ändern, können Sie dies bei Bedarf in int umwandeln.

Ein weiterer Grund ist, dass der Bereich der Doppelgänger viel größer ist als der von Inten. Es kann nicht möglich sein, alle Doubles auf Ints zu runden.





floor