Gegebene ganzzahlige Werte x
und geben sowohl y
C als auch C ++ als Quotient q = x/y
den Boden des Gleitkommaäquivalents zurück. Ich bin an einer Methode interessiert, stattdessen die Decke zurückzugeben. Zum Beispiel ceil(10/5)=2
und ceil(11/5)=3
.
Der offensichtliche Ansatz beinhaltet etwas wie:
q = x / y;
if (q * y < x) ++q;
Dies erfordert einen zusätzlichen Vergleich und eine zusätzliche Multiplikation. und andere Methoden, die ich gesehen habe (tatsächlich verwendet), beinhalten das Casting als float
oderdouble
. Gibt es eine direktere Methode, die die zusätzliche Multiplikation (oder eine zweite Division) und Verzweigung vermeidet und die auch das Casting als Gleitkommazahl vermeidet?
q = x/y + (x % y != 0);
ist. Es reicht einfach ausAntworten:
Für positive Zahlen
Aufrunden ...
oder (Vermeidung eines Überlaufs in x + y)
quelle
x/y
wie die Obergrenze der Division. C90 hat nicht angegeben, wie gerundet werden soll, und ich glaube auch nicht, dass der aktuelle C ++ - Standard dies tut.q = x / y;
Für positive Zahlen:
quelle
Die Antwort von Sparky ist ein Standardweg, um dieses Problem zu lösen, aber wie ich auch in meinem Kommentar geschrieben habe, laufen Sie Gefahr, überzulaufen. Dies kann durch Verwendung eines breiteren Typs gelöst werden, aber was ist, wenn Sie teilen möchten?
long long
s ?Die Antwort von Nathan Ernst bietet eine Lösung, beinhaltet jedoch einen Funktionsaufruf, eine Variablendeklaration und eine Bedingung, wodurch sie nicht kürzer als der OP-Code und wahrscheinlich sogar langsamer ist, da die Optimierung schwieriger ist.
Meine Lösung lautet:
Es ist etwas schneller als der OPs-Code, da das Modulo und die Division mit derselben Anweisung auf dem Prozessor ausgeführt werden, da der Compiler erkennen kann, dass sie äquivalent sind. Mindestens gcc 4.4.1 führt diese Optimierung mit dem Flag -O2 auf x86 durch.
Theoretisch könnte der Compiler den Funktionsaufruf in Nathan Ernsts Code einbinden und dasselbe ausgeben, aber gcc hat das nicht getan, als ich ihn getestet habe. Dies könnte daran liegen, dass der kompilierte Code an eine einzelne Version der Standardbibliothek gebunden wird.
Abschließend ist nichts davon auf einem modernen Computer von Bedeutung, es sei denn, Sie befinden sich in einer extrem engen Schleife und alle Ihre Daten befinden sich in Registern oder im L1-Cache. Andernfalls sind alle diese Lösungen gleich schnell, mit Ausnahme von Nathan Ernsts, der möglicherweise erheblich langsamer ist, wenn die Funktion aus dem Hauptspeicher abgerufen werden muss.
quelle
q = (x > 0)? 1 + (x - 1)/y: (x / y);
q = x / y + (x % y > 0);
ist einfacher als? :
Ausdruck?Sie können die
div
Funktion in cstdlib verwenden, um den Quotienten und den Rest in einem einzigen Aufruf abzurufen und dann die Obergrenze wie unten beschrieben separat zu behandelnquelle
return res.quot + !!res.rem;
:)Wie wäre es damit? (erfordert y nicht negativ, verwenden Sie dies also nicht in dem seltenen Fall, in dem y eine Variable ohne Nicht-Negativitätsgarantie ist)
Ich reduzierte mich auf
y/y
eins, eliminierte den Begriffx + y - 1
und damit jede Möglichkeit eines Überlaufs.Ich vermeide es,
x - 1
herumzuwickeln, wennx
es sich um einen vorzeichenlosen Typ handelt, der Null enthält.Bei Vorzeichen
x
werden Negativ und Null immer noch zu einem einzigen Fall zusammengefasst.Wahrscheinlich kein großer Vorteil für eine moderne Allzweck-CPU, aber dies wäre in einem eingebetteten System weitaus schneller als jede andere richtige Antwort.
quelle
Es gibt eine Lösung für positiv und negativ,
x
aber nur für positivy
mit nur 1 Division und ohne Zweige:Beachten Sie, wenn
x
positiv ist , ist die Division in Richtung Null, und wir sollten 1 hinzufügen, wenn die Erinnerung nicht Null ist.Wenn
x
negativ ist, dann ist die Division gegen Null, das ist es, was wir brauchen, und wir werden nichts hinzufügen, weilx % y
es nicht positiv istquelle
Dies funktioniert für positive oder negative Zahlen:
Wenn es einen Rest gibt, prüft, ob
x
undy
haben das gleiche Vorzeichen und fügt1
entsprechend hinzu .quelle
Ich hätte es lieber kommentiert, aber ich habe nicht genügend Wiederholungen.
Soweit mir bekannt ist, ist dies für positive Argumente und einen Divisor mit einer Potenz von 2 der schnellste Weg (getestet in CUDA):
Nur für generische positive Argumente mache ich das eher so:
quelle
q = x/y + !!(x % y);
sichq = x/y + (x % y == 0);
dieq = (x + y - 1) / y;
Lösungen in der heutigen CUDA behaupten und welche Leistung sie erbringen.vereinfachte generische Form,
Für eine allgemeinere Antwort bietet C ++ Funktionen für die Ganzzahldivision mit genau definierter Rundungsstrategie
quelle
Mit O3 kompilieren. Der Compiler führt die Optimierung gut durch.
quelle