((smallest) && (greater than -1)) fkt


  • Mod

    Und jetzt baust du einfach noch eben diese Bedingung ein und schon bist du fertig. Noch ein Tipp:

    if ((a>-1) && ((b>-1) && (a<b)) && ((c>-1) && (a<c))) return a;
    

    Hoffentlich habe ich mich nicht verklammert.

    ⚠ Wenn ich so drüber nachdenke wäre es aber vermutlich einfacher alle Werte in einen Container sortieren und hinterher den kleinsten größer -1 zu nehmen. Das wären dann nämlich im schlimmsten Fall 3 Vergleiche zum sortieren, je nach Container eventuell noch bis zu drei Verschiebungen und danach schlimmstenfalls 3 Vergleiche mit -1 (im Falle, dass alle <-1 sind). Das sind im Schnitt vermutlich deutlich weniger Operationen als mein erster Vorschlag, der, wenn ich ihn mir jetzt angucke, vielleicht doch nicht so sauber aussieht.



  • #include <algorithm>
    
    using namespace std;
    
    int fkt(int a, int b, int c)
    {
    	int ret = -1;
    
    	int res = min(min(a, b), c);
    
    	return res > ret ? res : ret;
    }
    


  • Ich glaube, so etwas sollte auch gehen

    int _1;
    	int _2;
    	int _3;
    	// ...
    	int min = max(max(max(-1,i),max(-1,j)),max(-1,k));
    	if(min!=-1)
    	{
    	}
    

    😃



  • belli: genial!!!!



  • Oder aber etwas unübersichtlicher:

    #include <algorithm>
    
    using namespace std;
    
    int fkt(int a, int b, int c)
    {
        return max(min(a, b), c), -1);
    }
    


  • Die Funktion von Belli liefert aber nicht das gewünschte Ergebnis oder?

    a = 1;
    b = -2;
    c = 5;

    liefert -1 obwohl das Ergebis 1 sein sollte oder?



  • Jo, da hab ich wohl nur die Hälfte der Aufgabe gelesen/verstanden ...



  • Die Variablennamen waren eben falsch, ansonsten

    int fkt(int a, int b, int c)
    {
    	return max(max(max(-1,a),max(-1,b)),max(-1,c));
    }
    

    funktioniert das immer.



  • ähmja schrieb:

    Die Variablennamen waren eben falsch, ansonsten

    int fkt(int a, int b, int c)
    {
    	return max(max(max(-1,a),max(-1,b)),max(-1,c));
    }
    

    funktioniert das immer.

    Echt? Das sieht für mich aus als würde er einfach den größten Wert zurück liefern 🙂 .



  • Sorry, hab die Aufgabenstellung nur halb gelesen...


  • Mod

    Hier mal was anderes:

    int temp[3]={a,b,c};
    std::sort(temp, temp+3);
    return * std::find_if(temp, temp+3, std::bind2nd(std::greater<int>(),-1))
    

    Ungetestet auf Syntaxfehler, aber um mal zu zeigen was ich oben meinte.

    Pro: Einfach erweiterbar auf N-Zahlen, leicht wartbar, leicht zu verstehen
    Contra: Overhead. Die Funktion wird immer noch sehr schnell sein, aber falls sie in einer zeitkritischen Schleife steht ist noch deutliche Optimierung möglich, indem man ausnutzt, dass es nur 3 Zahlen sind. sort und find sind nämlich ziemlicher Overkill um sie auf 3 Elemente anzuwenden. Eine sehr gute Implementierung von sort und ein optimierender Compiler mit Schleifenaufdröselung werden aber ein Ergebnis erzeugen, welches gleichwertig zu handgeschriebenem, optimierten Code ist. Es sollte daher also kein großer Nachteil sein. Eventuell ein eigenes, spezialisiertes sort für 3 Elemente schreiben.

    edit: Ups, die Bedingung für find_if war genau falsch rum. Korrigiert.



  • ähmja schrieb:

    Sorry, hab die Aufgabenstellung nur halb gelesen...

    Brauchst dich ja net zu entschuldigen 🙂 . Der Thread-Ersteller ist anscheinend mit den bekommenen Antworten zufrieden.

    Und solange er net Software entwickelt die womöglich meine Gesundheit beeinträchtigt, soll es mir auch recht sein.



  • Wieso nicht einfach

    #include <algorithm>
    #include <limits>
    using namespace std;
    
    template<typename T>
    T getsmallestmax(T a, T b, T c, T m)
    {
    	const T tmax = T(std::numeric_limits<T>::max);
    	a=max(a,m)==m?tmax:a;
    	b=max(b,m)==m?tmax:b;
    	c=max(c,m)==m?tmax:c;
    	return (a==b && a==c)?m:min(min(a,b),c);
    }
    
    void f()
    {
        getsmallestmax(1,2,3,-1);
    }
    


  • EDIT: Sorry, 2. Seite übersehen.



  • Da nach 4.7 (2) negative ints nach unsigned umgewandelt modulo 2^(Breite unsigned) genommen werden und dementsprechend im Ergebnis größer als von int darstellbare Werte sind, ist Folgendes möglich:

    #include <algorithm>
    #include <limits>
    
    int minmax(int x_p, int y_p, int z_p) {
      unsigned x = x_p,
               y = y_p,
               z = z_p;
      unsigned r = std::min(x, std::min(y, z));
      unsigned int_max = std::numeric_limits<int>::max();
    
      return r <= int_max ? static_cast<int>(r) : -1;
    }
    

    Auf allen gängigen Rechnern ginge auch

    int minmax(unsigned x, unsigned y, unsigned z) {
      return std::max(-1, static_cast<int>(std::min(x, std::min(y, z)));
    }
    

    ...aber streng genommen ist die Umwandlung von unsigned nach int außerhalb des von int darstellbaren Wertebereichs implementation-defined, und man sollte sich nicht ohne Not undefiniertes Verhalten einfangen.

    Der Vorteil des Ansatzes liegt darin, dass die Umwandlung von int nach unsigned in Zweierkomplementdarstellung rein konzeptuell ist und der größte Teil der Logik so auf allen gängigen Architekturen vom Compiler wegoptimiert werden kann.



  • .filmor schrieb:

    int babäm (int a, int b, int c)
    {
       if (a < 0)
          if (b < 0)
              if (c < 0)
                  return -1;
              else
                  return c;
          else
              return std::min(b, c);
       else
           if (b < 0)
               if (c < 0)
                   return a;
               else
                   return std::min(a, c);
           else
               if (c < 0)
                   return std::min(a, b);
               else
                   return std::min(std::min(a, b), c);
    }
    

    ´

    Ich hab es jetzt mal so wie .filmor gemacht...
    sein code ist zwar nicht 100% korrekt aber es funzt, auch wenn es ganz und gar nicht schön aussieht...



  • @Rumpelprogger:

    assert(greatestmax(1, 1, 1, -1) == 1);
    

    @seldon:
    Das hab ich vorher schonmal geschrieben und zwar so, dass der Compiler nicht über Vorzeichenverlust warnt 😉

    @threadstarter:

    int babäm (int a, int b, int c)
    {
       if (a < 0)
          if (b < 0)
              if (c < 0)
                  return -1;
              else
                  return c;
          else
              if (c < 0)
                  return b;
              else
                  return std::min(b, c);
       else
           if (b < 0)
               if (c < 0)
                   return a;
               else
                   return std::min(a, c);
           else
               if (c < 0)
                   return std::min(a, b);
               else
                   return std::min(std::min(a, b), c);
    }
    

    sollte korrekt sein. Du kannst das ganze auch rekursiv mit variadic templates machen 😉



  • Okay, in der letzten Zeile sollte

    return (a==m && a==b && a==c)?m:min(min(a,b),c);
    

    stehen. Der Nachteil ist auch, dass numeric_limits<T>::max für alle Werte ebenfalls min liefert. Der Vorteil allerdings ist, dass der Min-Wert frei wählbar ist.

    getsmallestmax(4.4f,4.3f,4.5f,4.35f);
    


  • seldon schrieb:

    Auf allen gängigen Rechnern ginge auch

    int minmax(unsigned x, unsigned y, unsigned z) {
      return std::max(-1, static_cast<int>(std::min(x, std::min(y, z)));
    }
    

    ...aber streng genommen ist die Umwandlung von unsigned nach int außerhalb des von int darstellbaren Wertebereichs implementation-defined, und man sollte sich nicht ohne Not undefiniertes Verhalten einfangen.

    1. Was bringt das, das nicht zu definieren?
    2. Ginge es so?

    int minmax(unsigned x, unsigned y, unsigned z)
    {
      return std::max(-1, (*((int *)(&(std::min(x, std::min(y, z))))));
    }
    


  • Zu 1.: Ich vermute, das hat historische Gründe. Nicht alle Computer haben die Zweierkomplementdarstellung benutzt; beispielsweise benutzten frühe PDPs, CDCs und UNIVACs das Einerkomplement, und einige frühe IBM-Mainframes benutzten überhaupt kein Komplement, sondern stellten einfach ein Vorzeichen vor den Betrag. Die UNIVAC 1100-Reihe wurde bis in die Achtziger Jahre fortgesetzt, also konnte man sich weder bei der Standardisierung von C noch bei der Entwicklung von C++ auf das Zweierkomplement verlassen.

    Zu 2.: Mit Pointergecaste bist du da keinesfalls besser dran. Das Ergebnis von

    int x = 2;
    unsigned y = *((unsigned*)&x);
    

    dürfte nicht definiert sein; der Standard schreibt nicht vor, dass int und unsigned gleichen Wertes das gleiche Bitmuster haben müssen. Außerdem versuchst du so, std::max(int, unsigned) aufzurufen, welches nicht existiert.


Anmelden zum Antworten