round() für Float in C++

Lesezeit: 11 Minuten

round fur Float in C
Roddy

Ich brauche eine einfache Gleitkomma-Rundungsfunktion, also:

double round(double);

round(0.1) = 0
round(-0.1) = 0
round(-0.9) = -1

ich kann finden ceil() und floor() in der math.h – aber nicht round().

Ist es in der Standard-C++-Bibliothek unter einem anderen Namen vorhanden oder fehlt es?

  • Wenn Sie die Zahl nur als gerundete Zahl ausgeben möchten, können Sie dies anscheinend tun std::cout << std::fixed << std::setprecision(0) << -0.9zum Beispiel.

    – Frank

    17. Februar 2011 um 18:05 Uhr

  • Schützen Sie dies … Neue Benutzer mit brillanten neuen Rundungsschemata sollten zuerst die vorhandenen Antworten lesen.

    – Shog9

    18. Februar 2011 um 20:33 Uhr

  • round ist seit C++11 in verfügbar <cmath>. Wenn Sie sich in Microsoft Visual Studio befinden, fehlt es leider immer noch: connect.microsoft.com/VisualStudio/feedback/details/775474/…

    – Alessandro Jacobson

    5. April 2013 um 8:29 Uhr

  • Wie ich in meiner Antwort feststelle, rollen Sie Ihre eigenen round hat viele Vorbehalte. Vor C++11 stützte sich der Standard auf C90, das nicht enthalten war round. C ++ 11 basiert auf C99, das dies hat round aber auch, wie ich angemerkt habe trunc die unterschiedliche Eigenschaften hat und je nach Anwendung geeigneter sein kann. Die meisten Antworten scheinen auch zu ignorieren, dass ein Benutzer möglicherweise einen ganzzahligen Typ zurückgeben möchte, der noch mehr Probleme hat.

    – Shafik Yaghmour

    23. Juni 2014 um 13:39 Uhr


  • @uvts_cvs Dies scheint kein Problem mit der neuesten Version von Visual Studio zu sein. live sehen.

    – Shafik Yaghmour

    23. Juni 2014 um 13:49 Uhr


round fur Float in C
Andreas Magnusson

Anmerkung des Herausgebers: Die folgende Antwort bietet eine vereinfachte Lösung, die mehrere Implementierungsfehler enthält (eine vollständige Erklärung finden Sie in der Antwort von Shafik Yaghmour). Beachten Sie, dass C++11 enthält std::round, std::lroundund std::llround als eingebaute bereits.

In der C++98-Standardbibliothek gibt es kein round(). Du kannst aber auch selbst einen schreiben. Das Folgende ist eine Implementierung von Runde-halb-auf:

double round(double d)
{
  return floor(d + 0.5);
}

Der wahrscheinliche Grund dafür, dass es in der C++98-Standardbibliothek keine Round-Funktion gibt, ist, dass sie tatsächlich auf verschiedene Arten implementiert werden kann. Das obige ist ein gängiger Weg, aber es gibt andere wie z rund-auf-gerade, was weniger voreingenommen und im Allgemeinen besser ist, wenn Sie viel runden; Es ist jedoch etwas komplexer zu implementieren.

  • Dies behandelt negative Zahlen nicht richtig. Die Antwort von litb ist richtig.

    – Registrierter Nutzer

    22. Mai 2009 um 22:02 Uhr

  • @InnerJoin: Ja, es behandelt negative Zahlen anders als die Antwort von litb, aber das macht es nicht “falsch”.

    – Roddy

    10. Juni 2009 um 19:59 Uhr

  • Durch das Hinzufügen von 0,5 vor dem Abschneiden wird bei mehreren Eingaben, einschließlich 0,49999999999999994, nicht auf die nächste ganze Zahl gerundet. Sehen blog.frama-c.com/index.php?post/2013/05/02/nearbyintf1

    – Pascal Cuoq

    4. Mai 2013 um 18:23 Uhr

  • @Sergi0: Es gibt kein “richtig” und “falsch”, weil es welche gibt mehr als eine Definition von Rundung die entscheiden, was zur Halbzeit passiert. Überprüfen Sie Ihre Fakten, bevor Sie ein Urteil fällen.

    – Jon

    25. November 2013 um 8:31 Uhr

  • @MuhammadAnnaqeeb: Du hast Recht, die Dinge haben sich seit der Veröffentlichung von C++11 enorm verbessert. Diese Frage wurde in einer anderen Zeit gestellt und beantwortet, als das Leben hart und die Freuden gering waren. Es bleibt hier als Ode an die Helden, die damals gelebt und gekämpft haben, und an die armen Seelen, die immer noch nicht in der Lage sind, moderne Werkzeuge zu benutzen.

    – Andreas Magnusson

    12. Februar 2014 um 13:40 Uhr

1647150613 265 round fur Float in C
Daniel Wolf

Boost bietet einen einfachen Satz von Rundungsfunktionen.

#include <boost/math/special_functions/round.hpp>

double a = boost::math::round(1.5); // Yields 2.0
int b = boost::math::iround(1.5); // Yields 2 as an integer

Weitere Informationen finden Sie unter Boost-Dokumentation.

Bearbeiten: Seit C++11 gibt es std::round, std::lroundund std::llround.

  • Ich habe in meinem Projekt bereits Boost verwendet, +1 dafür, viel besser als die Verwendung des naiven floor(value + 0.5) sich nähern!

    – Gustavo Maciel

    12. Juni 2014 um 0:51 Uhr

  • @GustavoMaciel Ich weiß, ich bin etwas spät im Spiel, aber die Boost-Implementierung ist es floor(value + 0.5).

    – n. 1.8e9-wo-ist-meine-Aktie m.

    18. Januar 2018 um 18:22 Uhr

  • Das geht eigentlich nicht: github.com/boostorg/math/blob/develop/include/boost/math/… 4 Jahre später möchte ich das auch sagen floor(value + 0.5) ist überhaupt nicht naiv, sondern hängt vom Kontext und der Art der Werte ab, die Sie runden möchten!

    – Gustavo Maciel

    25. Januar 2018 um 3:14 Uhr

1647150613 284 round fur Float in C
Shafik Yaghmur

Der C++03-Standard stützt sich auf den C90-Standard für das, was der Standard als bezeichnet Standard-C-Bibliothek die im Entwurf des C++03-Standards behandelt wird (N1804 ist ein öffentlich verfügbarer Standardentwurf, der C++03 am nächsten kommt) Sektion 1.2 Normative Verweisungen:

Die in Abschnitt 7 von ISO/IEC 9899:1990 und Abschnitt 7 von ISO/IEC 9899/Amd.1:1995 beschriebene Bibliothek wird im Folgenden als Standard-C-Bibliothek bezeichnet.1)

Wenn wir in die gehen C-Dokumentation für round, lround, llround auf cpreference wir können das sehen runden und verwandte Funktionen sind Teil von C99 und wird daher in C++03 oder früher nicht verfügbar sein.

In C++11 ändert sich dies, da C++11 auf dem Entwurf des C99-Standards für basiert C-Standardbibliothek und bietet daher std::round und für ganzzahlige Rückgabetypen std::lround, std::llround :

#include <iostream>
#include <cmath>

int main()
{
    std::cout << std::round( 0.4 ) << " " << std::lround( 0.4 ) << " " << std::llround( 0.4 ) << std::endl ;
    std::cout << std::round( 0.5 ) << " " << std::lround( 0.5 ) << " " << std::llround( 0.5 ) << std::endl ;
    std::cout << std::round( 0.6 ) << " " << std::lround( 0.6 ) << " " << std::llround( 0.6 ) << std::endl ;
}

Eine andere Option wäre auch ab C99 std::trunc welcher:

Berechnet die nächste ganze Zahl, die nicht größer als arg ist.

#include <iostream>
#include <cmath>

int main()
{
    std::cout << std::trunc( 0.4 ) << std::endl ;
    std::cout << std::trunc( 0.9 ) << std::endl ;
    std::cout << std::trunc( 1.1 ) << std::endl ;
    
}

Wenn Sie Nicht-C++11-Anwendungen unterstützen müssen, verwenden Sie am besten Runde, iround, lround, llround verstärken oder Boost-Trunk.

Es ist schwierig, seine eigene Version von Round zu rollen

Selber rollen lohnt sich da wohl nicht Schwieriger als es aussieht: Float auf die nächste Ganzzahl runden, Teil 1, Float auf die nächste Ganzzahl runden, Teil 2 und Float auf die nächste Ganzzahl runden, Teil 3 erklären:

Zum Beispiel eine gemeinsame Rolle, die Ihre Implementierung verwendet std::floor und hinzufügen 0.5 funktioniert nicht bei allen Eingängen:

double myround(double d)
{
  return std::floor(d + 0.5);
}

Eine Eingabe, für die dies fehlschlägt, ist 0.49999999999999994(live sehen).

Eine weitere gängige Implementierung besteht darin, einen Gleitkommatyp in einen ganzzahligen Typ umzuwandeln, der ein undefiniertes Verhalten hervorrufen kann, falls der ganzzahlige Teil nicht im Zieltyp dargestellt werden kann. Wir können dies aus dem Entwurf des C++-Standardabschnitts ersehen 4.9 Floating-Integral-Konvertierungen was sagt (Betonung von mir):

Ein Prvalue vom Typ Gleitkomma kann in einen Prvalue vom Typ Integer konvertiert werden. Die Konvertierung wird abgeschnitten; das heißt, der Bruchteil wird verworfen. Das Verhalten ist undefiniert, wenn der abgeschnittene Wert nicht im Zieltyp dargestellt werden kann.[…]

Zum Beispiel:

float myround(float f)
{
  return static_cast<float>( static_cast<unsigned int>( f ) ) ;
}

Gegeben std::numeric_limits<unsigned int>::max() ist 4294967295 dann folgender Aufruf:

myround( 4294967296.5f ) 

wird Überlauf verursachen, (live sehen).

Wir können sehen, wie schwierig das wirklich ist, wenn wir uns diese Antwort auf Concise way to implement round() in C? welche Referenzierung neuelibs Version von Single Precision Float Round. Es ist eine sehr lange Funktion für etwas, das einfach erscheint. Es scheint unwahrscheinlich, dass jemand ohne genaue Kenntnisse von Gleitkommaimplementierungen diese Funktion korrekt implementieren könnte:

float roundf(x)
{
  int signbit;
  __uint32_t w;
  /* Most significant word, least significant word. */
  int exponent_less_127;

  GET_FLOAT_WORD(w, x);

  /* Extract sign bit. */
  signbit = w & 0x80000000;

  /* Extract exponent field. */
  exponent_less_127 = (int)((w & 0x7f800000) >> 23) - 127;

  if (exponent_less_127 < 23)
    {
      if (exponent_less_127 < 0)
        {
          w &= 0x80000000;
          if (exponent_less_127 == -1)
            /* Result is +1.0 or -1.0. */
            w |= ((__uint32_t)127 << 23);
        }
      else
        {
          unsigned int exponent_mask = 0x007fffff >> exponent_less_127;
          if ((w & exponent_mask) == 0)
            /* x has an integral value. */
            return x;

          w += 0x00400000 >> exponent_less_127;
          w &= ~exponent_mask;
        }
    }
  else
    {
      if (exponent_less_127 == 128)
        /* x is NaN or infinite. */
        return x + x;
      else
        return x;
    }
  SET_FLOAT_WORD(x, w);
  return x;
}

Andererseits, wenn keine der anderen Lösungen verwendbar sind neuelib könnte möglicherweise eine Option sein, da es sich um eine gut getestete Implementierung handelt.

  • @downvoter bitte erklären, was verbessert werden kann? Die überwiegende Mehrheit der Antworten hier ist einfach falsch, da sie versuchen, ihre eigene Runde zu drehen, die alle in der einen oder anderen Form scheitern. Wenn in meiner Erklärung etwas fehlt, lassen Sie es mich bitte wissen.

    – Shafik Yaghmour

    27. Juli 2014 um 10:45 Uhr

  • Schöne vollständige Antwort – insbesondere der Teil knapp unter 0,5. Eine weitere Nische: round(-0.0). C-Spezifikation scheint nicht anzugeben. Ich würde erwarten -0.0 als Ergebnis.

    – chux – Wiedereinsetzung von Monica

    3. August 2015 um 19:23 Uhr

  • @chux interessant, und der IEEE 754-2008-Standard legt fest, dass beim Runden Vorzeichen von Nullen und Unendlichkeiten erhalten bleiben (siehe 5.9).

    – Ruslan

    8. März 2016 um 14:23 Uhr

  • @Shafik das ist eine großartige Antwort. Ich habe nie gedacht, dass sogar das Runden eine nicht triviale Operation ist.

    – Ruslan

    8. März 2016 um 14:24 Uhr

  • Das ist vielleicht erwähnenswert std::rint() ist oft vorzuziehen std::round() wenn C++11 aus numerischen und Leistungsgründen verfügbar ist. Im Gegensatz dazu verwendet es den aktuellen Rundungsmodus round()Spezialmodus von . Es kann auf x86 viel effizienter sein, wo rint kann in eine einzelne Anweisung eingebunden werden. (gcc und clang machen das auch ohne -ffast-math godbolt.org/g/5UsL2ewährend nur clang das nahezu Äquivalent einfügt nearbyint()) ARM bietet Unterstützung für einzelne Anweisungen für round()aber auf x86 kann es nur inline mit mehreren Anweisungen und nur mit -ffast-math

    – Peter Cordes

    17. November 2017 um 3:50 Uhr

Es kann erwähnenswert sein, dass Sie, wenn Sie ein ganzzahliges Ergebnis aus der Rundung erhalten möchten, es weder durch die Obergrenze noch durch die Untergrenze leiten müssen. Dh,

int round_int( double r ) {
    return (r > 0.0) ? (r + 0.5) : (r - 0.5); 
}

Es ist seit C++11 in cmath verfügbar (gemäß http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf)

#include <cmath>
#include <iostream>

int main(int argc, char** argv) {
  std::cout << "round(0.5):\t" << round(0.5) << std::endl;
  std::cout << "round(-0.5):\t" << round(-0.5) << std::endl;
  std::cout << "round(1.4):\t" << round(1.4) << std::endl;
  std::cout << "round(-1.4):\t" << round(-1.4) << std::endl;
  std::cout << "round(1.6):\t" << round(1.6) << std::endl;
  std::cout << "round(-1.6):\t" << round(-1.6) << std::endl;
  return 0;
}

Ausgabe:

round(0.5):  1
round(-0.5): -1
round(1.4):  1
round(-1.4): -1
round(1.6):  2
round(-1.6): -2

  • Es gibt auch lround und llround für integrale Ergebnisse

    – sp2danny

    23. Februar 2015 um 11:55 Uhr

  • @sp2danny: oder besser, lrint um den aktuellen Rundungsmodus zu verwenden anstatt round‘s funky weg von Null Tiebreak.

    – Peter Cordes

    17. November 2017 um 3:41 Uhr


  • Aber wie ist es verknüpft?

    – eri0o

    2. Dezember 2020 um 21:05 Uhr

1647150614 636 round fur Float in C
Tim Cooper

Es wird normalerweise als implementiert floor(value + 0.5).

Bearbeiten: und es wird wahrscheinlich nicht rund genannt, da es mindestens drei mir bekannte Rundungsalgorithmen gibt: Runden auf Null, Runden auf die nächste ganze Zahl und Runden des Bankers. Sie fragen nach dem Runden auf die nächste ganze Zahl.

  • Es gibt auch lround und llround für integrale Ergebnisse

    – sp2danny

    23. Februar 2015 um 11:55 Uhr

  • @sp2danny: oder besser, lrint um den aktuellen Rundungsmodus zu verwenden anstatt round‘s funky weg von Null Tiebreak.

    – Peter Cordes

    17. November 2017 um 3:41 Uhr


  • Aber wie ist es verknüpft?

    – eri0o

    2. Dezember 2020 um 21:05 Uhr

1647150614 855 round fur Float in C
Donal Fellows

Es gibt 2 Probleme, die wir betrachten:

  1. Rundungskonvertierungen
  2. Typkonvertierung.

Rundungskonvertierungen bedeuten Rundung ± Float/Double zum nächsten Floor/Ceil Float/Double. Vielleicht endet Ihr Problem hier. Aber wenn erwartet wird, dass Sie Int/Long zurückgeben, müssen Sie eine Typkonvertierung durchführen, und daher könnte das Problem “Overflow” Ihre Lösung treffen. Also, überprüfen Sie Ihre Funktion auf Fehler

long round(double x) {
   assert(x >= LONG_MIN-0.5);
   assert(x <= LONG_MAX+0.5);
   if (x >= 0)
      return (long) (x+0.5);
   return (long) (x-0.5);
}

#define round(x) ((x) < LONG_MIN-0.5 || (x) > LONG_MAX+0.5 ?\
      error() : ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))

von : http://www.cs.tut.fi/~jkorpela/round.html

  • Verwenden LONG_MIN-0.5 und LONG_MAX+0.5 führt zu Komplikationen, da die Mathematik möglicherweise nicht genau ist. LONG_MAX überschreiten darf double Präzision für exakte Umrechnung. Weitere wahrscheinlich wollen assert(x < LONG_MAX+0.5); (< vs <=) als LONG_MAX+0.5 kann genau darstellbar sein und (x)+0.5 kann ein genaues Ergebnis haben LONG_MAX+1 was fehlschlägt long Gießen. Andere Eckprobleme auch.

    – chux – Wiedereinsetzung von Monica

    30. August 2016 um 20:48 Uhr


  • Rufen Sie Ihre Funktion nicht auf round(double), gibt es bereits eine standardmäßige mathematische Bibliotheksfunktion dieses Namens (in C++11), was verwirrend ist. Verwenden std::lrint(x) wenn es verfügbar ist.

    – Peter Cordes

    17. November 2017 um 3:54 Uhr

996170cookie-checkround() für Float in C++

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy