std::ceil + divide + templates
-
Zu allererst mal:
für die, die es nicht aus dem kopf wissen: std::ceil ist das aufrundenJz erst mal hallo und Begrüßung und so^^
Ich habe ein Funktionstemplate und muss in diesem Runden und Dividieren - vereinfacht sieht das ganze so aus:
template <typename t1, typename t2, typename t3> t1 name(t2 a, t3 b) { return std::ceil (a / b); }Kein Problem, solange a oder b floats sind - aber wie würdet ihr das schreiben, damit es immer funktioniert?
Folgendes kann ich beim Aufruf garantieren:- a ist positiv, muss aber nicht zwangsläufig unsigned sein
- b ist positiv, muss aber nicht zwangsläufig unsigned sein
- -> das zu rundende Ergebnis ist positiv
- da t1 ein typedef auf einen size_type ist, wird es vermutlich size_t sein - auf jedenfall ein vorzeichenloser Typ
Meine alternative Idee wäre so etwas gewesen:
template <typename t1, typename t2, typename t3> t1 name(t2 a, t3 b) { return (a+b-1) / b; // (a+b-1)/b == a/b + 1 - 1/b }Ich nutze sie zur Zeit auch und es sieht auch so aus, als würden die Ergebnisse stimmen. Aber so richtig gefallen tut mir das auch wieder nicht - weil ich mir nicht ganz sicher bin, ob es _immer_ geht und auch nicht so richtig auf ne Beweis-Idee komme.
Sagt einfach mal, wie ihr es machen würdet...
Und falls ihr Fragen habt, dann fragt eben - bevor die Frage nach dem Warum kommt:
Das Ergebnis brauche ich, um zu wissen, wie viele Elemente ich in ein Array pushen muss - die beiden Parameter sind Transport-Kapazitäten, die aber auch ein signed typedef haben könnten - hier aber trotzdem immer positiv sind.Was ich eigtl nicht unbedingt möchte, ist einfach rumzu casten ^^
Ist ziemlich lang geworden, aber ich denke dafür wenigsten ganz gut beschrieben ^^
bb
-
1. Wieso können es verschiedene Typen sein?
2. Bei Integer Typen wird deine Funktion wohl kaum das machen, was du willst. Für a / b, wenn a und b ein Integertyp sind, dann wird das Ergebnis abgeschnitten, bevor es an die Funktion geht.
Wenn es wirklich für alle Typen sein soll, dann würde ich sowas machen:#include <boost/type_traits/is_floating_point.hpp> // ... template<typename ResultT, typename T1, typename T2> ResultT foo(T1 lhs, T2 rhs) { if(boost::is_floating_point<T1>::value || boost::is_floating_point<T2>::value) { return std::ceil(lhs / rhs); } else if(lhs % rhs) { return lhs / rhs + 1; } return lhs / rhs; }Oder sowas in der Richtung. Allerdings könnte man das wesentlich einfacher machen, wenn du die Typen ein wenig mehr einschränken könntest, was die sein können.
Grüssli
-
"Wieso können es verschiedene Typen sein"
Weil das eine die Kapazität eines Lagers ist - die also auch negativ sein kann (er hat Waren schon verkauft, aber noch nicht liefern können)
Die andere ist die eines Transporters/... - hab ich zwar lang überlegt, ob ich die gleiche nehme, aber fande ich aus vielerlei Gründen nicht gerade gut - deshalb hab ich mich dann auch dagegen entschieden..."Typen einschränken"
Weiß ich selbst noch nicht so genau - und ich wollte es auch allgemein gültig machen - genauer als oben geht es nicht (atm sind eben beides size_t weil es um abzählare waren geht - aber was, wenn ich iwann mal auf die Idee komme, dass ich irgend ne Maßeinheit haben will -> ich brauche float. Was, wenn ich mehr habe, als 2^32? Ich nehm __int64 - und danach? ^^Dravere schrieb:
Bei Integer Typen wird deine Funktion wohl kaum das machen, was du willst. Für a / b, wenn a und b ein Integertyp sind, dann wird das Ergebnis abgeschnitten, bevor es an die Funktion geht
Das hab ich doch gesagt:
unskilled schrieb:
Kein Problem, solange a oder b floats sind [...]
und deshalb dann die Lösung mit
return (a+b-1) / b;gepostet - aber diese mit der Frage versehen, ob sie denn wirklich allgemein gültig sei
oder ihr es anders machen würdet ^^Deine Lösung sieht aber fast hübscher aus ^^
bb
edit: boar - und vor allem warnt der compiler ja jz schon wieder rum (constant expression - da muss man sich wieder drum kümmern, dass man die warning deaktiviert ^^)
(a+1+1/b)/b gilt btw für alle b >= 1 ^^
-
unskilled schrieb:
return (a+b-1) / b;gepostet - aber diese mit der Frage versehen, ob sie denn wirklich allgemein gültig sei
oder ihr es anders machen würdet ^^Solange a und b Intergertypen sind und beide positiv, was du ja auch vorgegeben hast, dann glaube ich schon. Diese Lösung dürfte womöglich auch weniger Taktzyklen benötigen als meine. Allerdings schränkst du dich ein, was das Maximum betrifft, wegen dem
a + b.Ansonsten gebe ich dir nur den Rat, dass du es aktuell so löst, wie die Typen auch vorhanden sind. Wenn du später mal die Typen veränderst, passt du auch diese Rechnung an. Sehr wahrscheinlich wird dann sowieso eine Warnung geworfen werden, weil sich die Typen verändert haben. Du könntest dich aber auch mit einem
static_assertabsichern, damit du es ganz sicher nicht vergisst
Ich bin eigentlich der Meinung, dass dafür Templates zu verwenden, der falsche Weg ist.
Grüssli
-
Dravere schrieb:
Solange a und b Intergertypen sind und beide positiv, was du ja auch vorgegeben hast, dann glaube ich schon. Diese Lösung dürfte womöglich auch weniger Taktzyklen benötigen als meine. Allerdings schränkst du dich ein, was das Maximum betrifft, wegen dem
a + b.Ne - ich hatte nicht gesagt, dass es Integer seien ^^ Und es geht nicht für a<1 oder b<1

Wegen der Taktzyklen: Denke ich auch, aber da gibts - wie immer - andere Stellen, wo sehr viel mehr Rechenzeit (mit Sicherheit auch iwo unnötig) verbraten wird...Dravere schrieb:
Ich bin eigentlich der Meinung, dass dafür Templates zu verwenden, der falsche Weg ist.
Ich sehe eigtl genau hier den Einsatz von templates - aber diese Rechnung passt eben nicht so toll da rein - in die ganzen allgemein gültigen Funktionen -.-
Habs jz so gelöst, wie du vorgeschlagen hattest:
static bool CapacityIsFloatingPoint() { return (boost::is_floating_point<Tcapacity>::value || boost::is_floating_point<Tcapacity_transport>::value); } TSpokeContainer::size_type GetNeededTransports(Tcapacity have, Tcapacity need, Tcapacity_transport transport_capacity) { Tcapacity numerator = have - need; Tcapacity_transport &denominator = transport_capacity; //das sollte so und so immer gegeben sein... assert (! (numerator > 0) ^ (denominator > 0) ); //und -3 / -2 würde vom mathematischen her auch gehen - deshalb nen xor und kein or... assert ( denominator != 0 ); if(CapacityIsFloatingPoint()) return static_cast <TSpokeContainer::size_type> ( std::ceil (static_cast <float> (numerator) / denominator) ); if(numerator % denominator) return numerator / denominator + 1; return numerator / denominator; }Sieht zwar echt nich so hübsch aus, wie es davor aussah (und vor allem musste es jz eben wirklich in ne extra fkt), aber es geht wenigsten immer - Danke

bb