Matze: C++ Frage zu ceil()

Hallo!

Während ich dabei bin mich mit C++ zu beschäftigen,
habe ich mir zu Übungszwecken ein kleines Programm geschrieben.

#include <iostream>
#include <math.h>
using namespace std;

int e, a;   // Stückzahl, Verteilung (allocation)
float p, r; // Verpackungen, Restwert

int main ()
{
  cout << "Stückzahl:";
  cin >> e;
  cout << "Einheit(en) pro Verpackung:";
  cin >> a;
  p = ceil( e/a );
  r = e%a;
  cout << "Verpackungen: " << p << " Letzte Verpackung: " << r << " Stück" << endl;
  return 0;
}

Laut Beschreibung sollte ceil() doch in jedem Fall aufrunden.
Mein Test mit e = 20 und a = 7 ergibt mir aber 2.
Jetzt tippe ich darauf, dass aus int/int kein float p wird, obwohl p als float deklariert wurde.

Liege ich mit meiner Vermutung richtig?
Und wenn ja, wie bekomme ich den Restwert von e/a wenn der Modulus keine float-Variablen akzeptiert?
Oder wie bekomme ich einen float-Wert aus den beiden Integern?

Oder liegt mein Fehler ganz woanders?

Danke für Hinweise!

Grüße, Matze

  1. Ich habe den Code jetzt geändert:
    #include <iostream>
    #include <math.h>
    using namespace std;

    float p;        // Verpackungen
    int e, a, r;    // Stückzahl, Verteilung (allocation), Restwert

    int main ()
    {
      cout << "Stückzahl:";
      cin >> e;
      cout << "Einheit(en) pro Verpackung:";
      cin >> a;
      p = ceil( static_cast<float>(e) / static_cast<float>(a) );
      r = e%a;
      cout << "Verpackungen: " << p << " Letzte Verpackung: " << r << " Stück" << endl;
      return 0;
    }

    Das funktioniert soweit auch.

    Ich finde diese Zeile nur ein bisschen umständlich:
    p = ceil( static_cast<float>(e) / static_cast<float>(a) );
    Lässt sich das eleganter lösen? Sprich, nur 1 Aufruf von static_cast?

    Grüße, Matze

    1. Hello,

      Das funktioniert soweit auch.

      Ich finde diese Zeile nur ein bisschen umständlich:
      p = ceil( static_cast<float>(e) / static_cast<float>(a) );
      Lässt sich das eleganter lösen? Sprich, nur 1 Aufruf von static_cast?

      Hast Du schon mal versucht, den Devidenden (und ggf. auch den Divisor) auch als float-Typ zu deklarieren? MMn sollte das reichen.

      Liebe Grüße aus dem schönen Oberharz

      Tom vom Berg

      --
       ☻_
      /▌
      / \ Nur selber lernen macht schlau
      http://bergpost.annerschbarrich.de
      1. Hallo Tom,

        Hast Du schon mal versucht, den Devidenden (und ggf. auch den Divisor) auch als float-Typ zu deklarieren? MMn sollte das reichen.

        Ja sicher, es ist aber ziemlich blöd z.B. 1.34 Produkteinheiten auf 2 Verpackungen zu verteilen gelle? Man denke an z.B. Fernseher ;)
        1/2 Verpackung ergibt irgendwie auch nicht viel Sinn.
        Somit erwarte ich als Input nur integer.
        In bestimmten Fällen mag das sinnvoll sein, ich wollte aber extra Integer als Eingaben.

        Grüße, Matze

        1. Hello,

          Hast Du schon mal versucht, den Devidenden (und ggf. auch den Divisor) auch als float-Typ zu deklarieren? MMn sollte das reichen.

          Ja sicher, es ist aber ziemlich blöd z.B. 1.34 Produkteinheiten auf 2 Verpackungen zu verteilen gelle? Man denke an z.B. Fernseher ;)
          1/2 Verpackung ergibt irgendwie auch nicht viel Sinn.
          Somit erwarte ich als Input nur integer.
          In bestimmten Fällen mag das sinnvoll sein, ich wollte aber extra Integer als Eingaben.

          Da bringst Du aber Programmablaufplanung/-Design und Codierung durcheinander.

          Wer hindert Dich daran, zwei Integer an eine Funktion zu übergeben, deren Argumente aber als float dekalierte sind? In der Funktion rechnest Du mit deinen Integerwerten also als Float. Der Quotient ist dann auch ein Float-Typ und du kannst in Ruhe die Funktion ceil() darauf anwenden und dann das Ergebnis als Integer zurückgeben.

          Es ist alles nur eine Frage der Vereinbarung.

          Dein Compiler unterstützt dich nur so gut, wie Du ihn unterstützt :-))

          Liebe Grüße aus dem schönen Oberharz

          Tom vom Berg

          --
           ☻_
          /▌
          / \ Nur selber lernen macht schlau
          http://bergpost.annerschbarrich.de
          1. Hey Tom,

            Wer hindert Dich daran, zwei Integer an eine Funktion zu übergeben, deren Argumente aber als float dekalierte sind?

            Nichts, genau das mache ich doch:
            int e, a;
            p = ceil( static_cast<float>(e) / static_cast<float>(a) );

            Wieso sollte ich float-Werte als Eingaben erwarten?

            Grüße, Matze

            1. Hello,

              *seufz*

              Wer hindert Dich daran, zwei Integer an eine Funktion zu übergeben, deren Argumente aber als float dekalierte sind?

              Nichts, genau das mache ich doch:
              int e, a;
              p = ceil( static_cast<float>(e) / static_cast<float>(a) );

              Wieso sollte ich float-Werte als Eingaben erwarten?

              Bitte baue Dir eine Funktion, die die Aufgabe des Quantisierens übernimmt. Formuliere jede Teilaufgabe aus und gewöhne Dir nicht an, alles möglichst in eine Zeile zu quetschen.

              Mehr Zeilen im Quellcode bedeuten keinesfalls, dass Dein compiliertes Programm nachher langsamer läuft oder länger wird, sondern nur, dass der Quellcode schneller zu verstehen ist von Menschen, die ihn lesen müssen.

              Liebe Grüße aus dem schönen Oberharz

              Tom vom Berg

              --
               ☻_
              /▌
              / \ Nur selber lernen macht schlau
              http://bergpost.annerschbarrich.de
              1. *seufz*

                Ja, *seufz*. Ich befürchte ich versteh nicht was du mir sagen willst.

                Bitte baue Dir eine Funktion, die die Aufgabe des Quantisierens übernimmt.

                Ist das in dem Fall nicht ein bisschen weit gegriffen?
                Wenn so eine Funktion sinnvoll sein soll, müsste sie wohl alle Variablen-Typen berücksichtigen.
                Das brauch ich bei so einer kleinen Übung doch aber gar nicht.

                Formuliere jede Teilaufgabe aus und gewöhne Dir nicht an, alles möglichst in eine Zeile zu quetschen.

                Wie hättest du es gemacht? Oder besser wie sähe dein Vorschlag mit der zusätzlichen Funktion aus?

                Mehr Zeilen im Quellcode bedeuten keinesfalls, dass Dein compiliertes Programm nachher langsamer läuft

                Zusätzliche Funktionsaufrufe aber.

                Grüße, Matze

                1. Hello,

                  Wie hättest du es gemacht? Oder besser wie sähe dein Vorschlag mit der zusätzlichen Funktion aus?

                  Es ist sauberer, Statementseqenzen, die immer wieder auftreten, als Funktionen zu verfassen und sie nicht jedesmal wieder explizit hinzuschreiben. Oder wolltest Du Dein Programm auf minimale Anzahl Takte tunen?

                  Eine Tutorialseite hatte ich Dir übrigens verlinkt.

                  int verpackungen ( float a, float b)
                    {
                       return ceil( a/b );
                    }

                  Mehr benötigst Du mMn nicht. In die Floats müsstest Du jetzt auch Integers reinstecken dürfen, ohne dass der Compiler meckert, es sei denn, dass Du ihn auf strict umgestellt hast.
                  Normalerweise werden die kleineren Typen im nächst größeren automatisch gecastet. So habe ich es jedenfalls in Erinnerung.

                  Leider kann ich das Funktiönchen jetzt nicht ausprobieren, weil ich gerade keinen C-Compiler gängig habe... Musst Du also mal selber machen.

                  Liebe Grüße aus dem schönen Oberharz

                  Tom vom Berg

                  --
                   ☻_
                  /▌
                  / \ Nur selber lernen macht schlau
                  http://bergpost.annerschbarrich.de
                  1. Hallo Tom,

                    Es ist sauberer, Statementseqenzen, die immer wieder auftreten, als Funktionen zu verfassen und sie nicht jedesmal wieder explizit hinzuschreiben.

                    Du hast recht und ich hatte dich auch irgendwie missverstanden.
                    Ich dachte du meintest explizit die Typumwandlung in eine Funktion zu packen (also ohne die Bearbeitung durch ceil()).
                    Ich bin diese Typumwandlung auch einfach noch nicht gewöhnt.

                    Eine Tutorialseite hatte ich Dir übrigens verlinkt.

                    Ich lese gerade so viele Tutorials... ;)

                    Leider kann ich das Funktiönchen jetzt nicht ausprobieren, weil ich gerade keinen C-Compiler gängig habe... Musst Du also mal selber machen.

                    ||=== test, Debug ===|
                    In function int verpackungen(float, float)': warning: converting to int' from `double'|
                    ||=== Erstellen beendet: 0 Fehler, 1 Warnungen===|

                    Funktioniert wunderbar.

                    Grüße, Matze

                    1. Hello,

                      Leider kann ich das Funktiönchen jetzt nicht ausprobieren, weil ich gerade keinen C-Compiler gängig habe... Musst Du also mal selber machen.

                      ||=== test, Debug ===|
                      In function int verpackungen(float, float)': warning: converting to int' from `double'|
                      ||=== Erstellen beendet: 0 Fehler, 1 Warnungen===|

                      Dein Compiler ist nett zu dir und warnt Dich wegen des Verlustes bei der Funktion ceil(), denn die liefert ja nur einen Integer. Da dieser Verlust hier aber gewollt ist von Dir, kannst Du (im Kopf) einen Haken dranmachen :-)

                      Funktioniert wunderbar.

                      Hatte ich auch gehofft.

                      Und Du siehst, so kann man auch mit kleinen Sachen, der Lesbarkeit eine Freude machen.

                      Liebe Grüße aus dem schönen Oberharz

                      Tom vom Berg

                      --
                       ☻_
                      /▌
                      / \ Nur selber lernen macht schlau
                      http://bergpost.annerschbarrich.de
                      1. Hey Tom,

                        Und Du siehst, so kann man auch mit kleinen Sachen, der Lesbarkeit eine Freude machen.

                        jawoll, und ich hab auch gelernt, dass es doch ein bisschen automatische Typ-Umwandlung in C++ gibt :)

                        Herzlichen dank!

                        Matze

                      2. Tach,

                        Dein Compiler ist nett zu dir und warnt Dich wegen des Verlustes bei der Funktion ceil(), denn die liefert ja nur einen Integer.

                        ceil (in C) liefert keinen Integer sondern einen Double, in C++ gibt es auch noch Überladungen für float und long double, wenn ich mich nicht irre, die liefern aber auch jeweils das zurück, was man reinsteckt.

                        Da dieser Verlust hier aber gewollt ist von Dir, kannst Du (im Kopf) einen Haken dranmachen :-)

                        Ich glaube die Funktion ist schlecht, da sie für große floats falsche Werte liefert, die Signatur sollte eher "int verpackungen(int, int);" sein und es sollte innerhalb der Funktion gecastet werden.

                        Alternativ könnte man das ganze einfach auch mit Integer-Methoden berechnen:

                          
                        int verpackungen(int x, int y){  
                          return x/y + (x%y > 0);  
                        }  
                        
                        

                        mfg
                        Woodfighter

                        1. Hello,

                          Ich glaube die Funktion ist schlecht, da sie für große floats falsche Werte liefert, die Signatur sollte eher "int verpackungen(int, int);" sein und es sollte innerhalb der Funktion gecastet werden.

                          Stimmt auch wieder. Das hatte ich jetzt nicht bedacht.

                          Dann lohnt sich die Funktion doch wenigstens auch :-)

                          Liebe Grüße aus dem schönen Oberharz

                          Tom vom Berg

                          --
                           ☻_
                          /▌
                          / \ Nur selber lernen macht schlau
                          http://bergpost.annerschbarrich.de
              2. Hallo,

                Bitte baue Dir eine Funktion, die die Aufgabe des Quantisierens übernimmt. Formuliere jede Teilaufgabe aus und gewöhne Dir nicht an, alles möglichst in eine Zeile zu quetschen.

                nein, nur da, wo es sinnvoll ist.

                Mehr Zeilen im Quellcode bedeuten keinesfalls, dass Dein compiliertes Programm nachher langsamer läuft oder länger wird, sondern nur, dass der Quellcode schneller zu verstehen ist von Menschen, die ihn lesen müssen.

                Vielleicht geht *dir* das so, und vermutlich bist du damit auch kein Einzelfall.
                Ich kann Programmcode aber wesentlich leichter lesen und verstehen, wenn ein Denkschritt auch kompakt formuliert und eben *nicht* auf mehrere Teilanweisungen verteilt ist. Das macht die Sache für mich unübersichtlich.

                So long,
                 Martin

                --
                Ist die Katze gesund,
                freut sich der Hund.
                1. Hello,

                  Ich kann Programmcode aber wesentlich leichter lesen und verstehen, wenn ein Denkschritt auch kompakt formuliert und eben *nicht* auf mehrere Teilanweisungen verteilt ist. Das macht die Sache für mich unübersichtlich.

                  Wie das auf Dich wirkt, ist für nachvollziehbaren Programmierstil eigentlich unerheblich.

                  Die benutzen Abbildungen der Wirklichkeit auf die Programmiersprache (Statements) sollten immer eindeutig bleiben. Je kleiner man sie macht, desto weniger kann man daran herumdeuteln. Je kleiner sie sind, desto eher kann ein Nachleser ahnen, was der Urheber sich dabei mal gedacht hat.

                  Es macht i.d.R. weit über zehnmal mehr Arbeit, verschachtelte Statements [1] später zu "reengineeren", als es einem Urheber Mühe machen würde, diese explizit auszuformulieren und auf mehrere Zeilen aufzuteilen.

                  Jeder Betrieb, der ein "Coding-Style-Controlling" betreibt, wird davon spätestens mittelfristig wirtschaftlich profitieren.

                  [1] speziell, wenn sie Denkfehler enthalten. Denkfehlerfreie muss man seltener nochmal neu überdenken.

                  Liebe Grüße aus dem schönen Oberharz

                  Tom vom Berg

                  --
                   ☻_
                  /▌
                  / \ Nur selber lernen macht schlau
                  http://bergpost.annerschbarrich.de
                  1. Die benutzen Abbildungen der Wirklichkeit auf die Programmiersprache (Statements) sollten immer eindeutig bleiben. Je kleiner man sie macht, desto weniger kann man daran herumdeuteln. Je kleiner sie sind, desto eher kann ein Nachleser ahnen, was der Urheber sich dabei mal gedacht hat.

                    Exzessive und übereilte Abstraktionen "im Kleinen" mit (zwangsläufig) frei gewählten Bezeichnern können die Erkennbarkeit der Intention des Urhebers wiederum mindern.

                    Ich bin da bei Martin: nur da, wo es sinnvoll ist - worüber sich im Detail natürlich trefflich streiten lässt.

                  2. Hi,

                    Ich kann Programmcode aber wesentlich leichter lesen und verstehen, wenn ein Denkschritt auch kompakt formuliert und eben *nicht* auf mehrere Teilanweisungen verteilt ist. Das macht die Sache für mich unübersichtlich.
                    Wie das auf Dich wirkt, ist für nachvollziehbaren Programmierstil eigentlich unerheblich.

                    ja und nein. Ich wollte damit sagen: Was "nachvollziehbar" ist, ist sehr subjektiv.

                    Die benutzen Abbildungen der Wirklichkeit auf die Programmiersprache (Statements) sollten immer eindeutig bleiben. Je kleiner man sie macht, desto weniger kann man daran herumdeuteln.

                    Richtig, aber sie sollten nicht so fein granuliert werden, dass der Zusammenhang verlorengeht.

                    Je kleiner sie sind, desto eher kann ein Nachleser ahnen, was der Urheber sich dabei mal gedacht hat.

                    Eben nicht. Das Extrembeispiel ist Assembler. Da hast du den Ablauf *wirklich* auf elementare Einzelschritte heruntergebrochen. Leichter nachvollziehbar wird es dadurch nicht; du musst immer einen ganzen Block von Anweisungen betrachten, um den Sinn zu erkennen (von sorgfältiger Kommentierung des Codes, die meist vernachlässigt wird, ganz zu schweigen).

                    Es macht i.d.R. weit über zehnmal mehr Arbeit, verschachtelte Statements [1] später zu "reengineeren", als es einem Urheber Mühe machen würde, diese explizit auszuformulieren und auf mehrere Zeilen aufzuteilen.

                    Geht mir nicht so. Wenn der Urheber sich die Mühe gemacht hat, Anweisungen, die in einem direkten Zusammenhang stehen, auf mehrere Zeilen aufzudröseln, bin ich bestrebt, sie erst wieder zusammenzufassen, damit ich den Zusammenhang besser erkenne.

                    Jeder Betrieb, der ein "Coding-Style-Controlling" betreibt, wird davon spätestens mittelfristig wirtschaftlich profitieren.

                    Das halte ich angesichts der von Mensch zu Mensch unterschiedlichen Auffassungsgabe und Mustererkennung für ein Gerücht - zumal ich mir keinen Coding Style aufzwingen lasse, der *mir* das Verstehen und Erfassen erschwert.

                    [1] speziell, wenn sie Denkfehler enthalten. Denkfehlerfreie muss man seltener nochmal neu überdenken.

                    Wird aber auch oft genug gemacht ... ;-)

                    Ciao,
                     Martin

                    --
                    Vater Staat bringt uns noch alle unter Mutter Erde.
        2. moin matze,

          Ja sicher, es ist aber ziemlich blöd z.B. 1.34 Produkteinheiten auf 2 Verpackungen zu verteilen gelle? Man denke an z.B. Fernseher ;)
          1/2 Verpackung ergibt irgendwie auch nicht viel Sinn.

          das kommt drauf an, wir verwenden sogar vier nachkommastellen für die menge, die durchaus auch mit 0.5 besetzt sein kann. sicherlich weniger für produkte wie fernseher, aber bei anderen produkten wie zement, salz, etc. macht so was schon sinn, da du nicht immer die volle einheit verkaufen willst.

          Ilja

          1. Hey Ilja!

            das kommt drauf an, wir verwenden sogar vier nachkommastellen für die menge, die durchaus auch mit 0.5 besetzt sein kann. sicherlich weniger für produkte wie fernseher, aber bei anderen produkten wie zement, salz, etc. macht so was schon sinn, da du nicht immer die volle einheit verkaufen willst.

            Natürlich. Man kann auch halbe Brote kaufen. Bei der Verpackung wird es da aber schon schwierieger.
            Gut, es gibt auch Bierkisten mit 11 Flaschen oder Eierpappen mit 6, 10 oder mehr Plätzen aber es bleibt 1 ganze Verpackung. Mir erscheint es beim Programmieren halt unlogisch solche Sachen in einen anderen Kontext zu würfeln nur weil es gerade bequem erscheint.

            Mir ging es in meinem Beispiel aber auch explizit um den Interger bzw. das Problem, dass ich bei der Umwandlung zur float-Verarbeitung hatte.

            Grüße, Matze

            1. moin matze,

              Mir ging es in meinem Beispiel aber auch explizit um den Interger bzw. das Problem, dass ich bei der Umwandlung zur float-Verarbeitung hatte.

              davon habe ich viel zu wenig ahnung, als dass ich mich bei c++ einmischen würde. wollte dir nur den fachlichen hinweis geben, dass es auch halbe brote gibt, wie du als sehr schönes beispiel angebracht hast. da es aber grundsätzlich eher um was anderes ging, spielt das auch nicht eine so große rolle, sollte man aber im hinterkopf haben, falls man mal rechnungen modellieren muss. ;-)

              Ilja

  2. Hi,

    int e, a;   // Stückzahl, Verteilung (allocation)
      p = ceil( e/a );
    Laut Beschreibung sollte ceil() doch in jedem Fall aufrunden.

    Tut es auch.

    Zuerst wird e/a berechnet. Beides sind int, also wird nach int-Regeln gerechnet: 20/7 ist demnach 2, der Rest fällt bei int-Berechnung unter den Tisch.

    Dann kommt ceil ins Spiel. Da ceil ein float erwartet, wird aus der 2 eine 2.0, ceil von 2.0 ist 2.0 ...

    Jetzt tippe ich darauf, dass aus int/int kein float p wird, obwohl p als float deklariert wurde.

    Die Umwandlung in float findet später statt als Du es gerne hättest.

    Und wenn ja, wie bekomme ich den Restwert von e/a wenn der Modulus keine float-Variablen akzeptiert?

    So, wie Du es bei

    r = e%a;

    bereits machst.

    Oder wie bekomme ich einen float-Wert aus den beiden Integern?

    Mindestens einen der zwei Werte zu float umwandeln (z.B. durch cast oder durch Zuweisung an eine float-Variable) vor der Division.

    cu,
    Andreas

    --
    Warum nennt sich Andreas hier MudGuard?
    O o ostern ...
    Fachfragen per Mail sind frech, werden ignoriert. Das Forum existiert.
    1. Hallo Andreas,

      Mindestens einen der zwei Werte zu float umwandeln (z.B. durch cast oder durch Zuweisung an eine float-Variable) vor der Division.

      ach stimmt, die Möglichkeit gibts ja auch noch.
      Umkopieren mag ich aber nicht besonders, von daher ist static_cast wohl gar keine so dummer Lösung.

      Danke und Grüße, Matze

  3. Hi!

    int e, a;   // Stückzahl, Verteilung (allocation)
    float p, r; // Verpackungen, Restwert
      p = ceil( e/a );

    Laut Beschreibung sollte ceil() doch in jedem Fall aufrunden.

    Es rundet auch auf, allerdings hast du ein Verständnisproblem, was die Reihenfolge der Berechnungen angeht. Ein Ausdruck schaut nicht nach, wo er nach seiner Berechnung landen soll. Er wird erst berechnet und dann übergeben oder zugewiesen. Und Operatoren orientieren sich auch nur an den Operanden.

    Mein Test mit e = 20 und a = 7 ergibt mir aber 2.
    Jetzt tippe ich darauf, dass aus int/int kein float p wird, obwohl p als float deklariert wurde.

    Das p interessiert überhaupt nicht, wenn es darum geht zunächst e/a zu berechnen. Das ist eine Integer-Division, deren Ergebnis ein Integer ist, also 2. Dann übergibst du die int-2 der Funktion ceil, die gern double/float hätte, also gibt es da einen impliziten Typecast von int-2 zu einer double/float-2. Jetzt erst kommt das p ins Spiel, um das Ergebnis von ceil() aufzunehmen. Dabei gibt es gegebenenfalls noch einen Typecast, wenn double nach float gecastet weren muss.

    Und wenn ja, wie bekomme ich den Restwert von e/a wenn der Modulus keine float-Variablen akzeptiert?

    Sollte e % a nicht den Rest liefern?

    Oder wie bekomme ich einen float-Wert aus den beiden Integern?

    Typecasts, hast du ja schon rausgefunden.

    Lo!

    1. Hallo dedlfix,

      Es rundet auch auf, allerdings hast du ein Verständnisproblem, was die Reihenfolge der Berechnungen angeht.

      Ja, hatte ich. Danke für die Erklärung.

      Und wenn ja, wie bekomme ich den Restwert von e/a wenn der Modulus keine float-Variablen akzeptiert?
      Sollte e % a nicht den Rest liefern?

      Ja, aber dafür müssen e und a halt Integer sein.
      Wenn ich e und a am Anfang als float deklariere muss ich sie für den Modulus umwandeln. (es reicht also doch nicht, einfach float draus zu machen wie ich Tom geantwortet hatte)
      Wenn e und a am Anfang Integer sind muss ich sie für ceil() umwandeln. Da liegt der Hund begraben :)

      Typecasts, hast du ja schon rausgefunden.

      Meine Vermutung am Anfang war ja gar nicht so falsch, da lag die Lösung nicht mehr weit entfernt. Für das volle Verständnis gibt es so nette Erklärungen wie deine :)

      Danke und Grüße, Matze