((smallest) && (greater than -1)) fkt
-
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.
-
seldon schrieb:
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.
Ups, das soll natürlich ein Cast zu int sein. Ja, nach deiner Argumentation zu 1. ist es natürlich logisch, dass 2. nicht besser ist. Aber wenn aus historischen Gründen der Cast von unsigned zu int undefiniert ist, warum hast du dann nichts gegen einen Cast von int zu unsigned?
-
Weil der in 4.7 (2) (Integral conversions) definiert ist:
ISO/IEC 14882:2003 4.7 (2) schrieb:
If the destination type is unsigned, the resulting value is the least unsigned integer congruent to the source integer (modulo 2n where n is the number of bits used to represent the unsigned type). [Note: In a two’s complement representation, this conversion is conceptual and there is no change in the bit pattern (if there is no truncation). ]
-
seldon schrieb:
Weil der in 4.7 (2) (Integral conversions) definiert ist:
ISO/IEC 14882:2003 4.7 (2) schrieb:
If the destination type is unsigned, the resulting value is the least unsigned integer congruent to the source integer (modulo 2n where n is the number of bits used to represent the unsigned type). [Note: In a two’s complement representation, this conversion is conceptual and there is no change in the bit pattern (if there is no truncation). ]
Das verstehe ich zwar nicht ganz, aber ok, das ist definiert. Jetzt verstehe ich aber wiederum nicht, warum man die eine Richtung definiert hat und die andere nicht.
