403 Stimmen

Wie rundet man das Ergebnis einer Integer-Division auf?

Ich denke insbesondere darüber nach, wie ich Paginierungssteuerelemente anzeigen soll, wenn ich eine Sprache wie C# oder Java verwende.

Wenn ich x Elemente habe, die ich in Abschnitten von y pro Seite anzeigen möchte, wie viele Seiten werden benötigt?

1 Stimmen

Fehlt mir etwas? y/x + 1 funktioniert gut (vorausgesetzt, Sie wissen, dass der /-Operator immer abrundet).

69 Stimmen

@ rikkit - wenn y und x gleich sind, ist y/x + 1 auch eins zu hoch.

1 Stimmen

Für alle, die dies gerade erst entdecken, antwortet diese Antwort auf eine doppelte Frage überflüssige Konvertierungen in doppelte und vermeidet Überlaufprobleme, zusätzlich zu einer klaren Erklärung.

586voto

Ian Nelson Punkte 53679

Ich habe eine elegante Lösung gefunden:

int pageCount = (Datensätze + recordsPerPage - 1) / recordsPerPage;

Quelle: Zahlenumwandlung, Roland Backhouse, 2001

15 Stimmen

-1 aufgrund des Überlaufbugs, den Brandon DuRette aufgezeigt hat.

37 Stimmen

Herr Offensichtlich sagt: Denken Sie daran, sicherzustellen, dass recordsPerPage nicht null ist

7 Stimmen

Gute Arbeit, ich kann nicht glauben, dass C# keine Ganzzahl-Decke hat.

251voto

rjmunro Punkte 25846

Die Konvertierung in Gleitkommazahlen und zurück scheint auf der CPU-Ebene eine enorme Zeitverschwendung zu sein.

Ian Nelsons Lösung:

int pageCount = (records + recordsPerPage - 1) / recordsPerPage;

Kann vereinfacht werden zu:

int pageCount = ((records - 1) / recordsPerPage) + 1;

AFAICS hat dies nicht das Überlaufproblem, das Brandon DuRette darauf hingewiesen hat, und da es nur einmal verwendet wird, müssen Sie die recordsPerPage nicht extra speichern, wenn es von einer teuren Funktion kommt, um den Wert aus einer Konfigurationsdatei oder Ähnlichem abzurufen.

D.h. dies könnte ineffizient sein, wenn config.fetch_value eine Datenbankabfrage oder Ähnliches verwendet:

int pageCount = (records + config.fetch_value('records per page') - 1) / config.fetch_value('records per page');

Dies erstellt eine Variable, die Sie nicht wirklich benötigen und die vermutlich (geringe) Speicherimplikationen hat und einfach zu viel Tipparbeit ist:

int recordsPerPage = config.fetch_value('records per page')
int pageCount = (records + recordsPerPage - 1) / recordsPerPage;

Dies ist alles in einer Zeile und ruft die Daten nur einmal ab:

int pageCount = (records - 1) / config.fetch_value('records per page') + 1;

7 Stimmen

+1, das Problem, dass bei null Datensätzen immer noch 1 Seitenzahl zurückgegeben wird, ist tatsächlich praktisch, da ich trotzdem eine Seite anzeigen möchte, die die Platzhalter-/Fake-Zeile "Keine Datensätze entsprechen Ihren Kriterien" anzeigt und jegliche "0 Seitenzahl"-Probleme in der verwendeten Paginierungssteuerung vermeidet.

36 Stimmen

Bitte beachten Sie, dass die beiden Lösungen für null Datensätze keine gleiche pageCount zurückgeben. Diese vereinfachte Version liefert 1 pageCount für null Datensätze, während die Roland Backhouse-Version 0 pageCount zurückgibt. Gut, wenn Sie das wünschen, aber die beiden Gleichungen sind nicht äquivalent, wenn sie von C#/Java Style Integer-Division durchgeführt werden.

13 Stimmen

Kleine Änderung zur Klarstellung für Personen, die es überfliegen und die bodmas übersehen, wenn sie zur Vereinfachung der Nelson-Lösung wechseln (wie ich es das erste Mal gemacht habe!), die Vereinfachung mit Klammern lautet ... int pageCount = ((records - 1) / recordsPerPage) + 1;

101voto

Huppie Punkte 10951

Für C# ist die Lösung, die Werte in eine Double zu konvertieren (da Math.Ceiling eine Double erfordert):

int nPages = (int)Math.Ceiling((double)nItems / (double)nItemsPerPage);

In Java sollten Sie das Gleiche mit Math.ceil() tun.

4 Stimmen

Warum ist diese Antwort so weit unten, wenn der Ersteller explizit nach C# fragt?

3 Stimmen

Du musst auch die Ausgabe in int umwandeln, weil Math.Ceiling einen double oder decimal zurückgibt, abhängig von den Eingabetypen.

26 Stimmen

Weil es äußerst ineffizient ist

87voto

Nick Berardi Punkte 53415

Dies sollte Ihnen geben, was Sie wollen. Sie möchten definitiv x Artikel durch y Artikel pro Seite, das Problem ist, wenn ungerade Zahlen auftauchen, also wenn es eine Teilseite gibt, möchten wir auch eine Seite hinzufügen.

int x = anzahl_der_artikel;
int y = artikel_pro_seite;

// ohne Bibliothek
int seiten = x / y + (x % y > 0 ? 1 : 0)

// mit Bibliothek
int seiten = (int)Math.Ceiling((double)x / (double)y);

9 Stimmen

X/y + !!(x % y) vermeidet den Zweig für C-ähnliche Sprachen. Die Chancen stehen jedoch gut, dass Ihr Compiler das sowieso macht.

3 Stimmen

+1 für das Nichtüberlaufen wie in den obigen Antworten ... auch wenn das Umwandeln von int in double nur für Math.ceiling und dann wieder zurück eine schlechte Idee in leistungssensitivem Code ist.

4 Stimmen

@RhysUlerich das funktioniert nicht in C# (man kann einen int nicht direkt in ein bool konvertieren). rjmunros Lösung ist meiner Meinung nach der einzige Weg, um auf Verzweigungen zu verzichten.

19voto

Brandon DuRette Punkte 4730

Die ganzzahlige Mathematiklösung, die Ian zur Verfügung gestellt hat, ist gut, leidet aber unter einem Ganzzahlüberlauffehler. Wenn man annimmt, dass die Variablen alle int sind, könnte die Lösung umgeschrieben werden, um die long Mathematik zu verwenden und den Fehler zu vermeiden:

int pageCount = (-1L + records + recordsPerPage) / recordsPerPage;

Wenn records eine long ist, bleibt der Fehler bestehen. Die Moduluslösung hat den Fehler nicht.

6 Stimmen

Ich denke nicht, dass Sie realistischerweise diesen Fehler im dargestellten Szenario finden werden. 2^31 Datensätze sind ziemlich viele, um sich durchzublättern.

8 Stimmen

1 Stimmen

@finnw: Soweit ich das sehe, gibt es kein wirkliches Beispiel auf dieser Seite, sondern nur einen Bericht über jemanden, der den Fehler in einem theoretischen Szenario gefunden hat.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X