Java mit Math.ceil auf ein int aufrunden


101
int total = (int) Math.ceil(157/32);

Warum gibt es immer noch 4 zurück? 157/32 = 4.90625Ich muss mich umsehen, ich habe mich umgesehen und das scheint die richtige Methode zu sein.

Ich habe es totalals doubleTyp versucht , bekomme aber 4.0.

Was mache ich falsch?

Antworten:


187

Sie 157/32teilen zwei Ganzzahlen miteinander, was immer zu einer abgerundeten Ganzzahl führt. Deshalb (int) Math.ceil(...)macht der nichts. Es gibt drei mögliche Lösungen, um das zu erreichen, was Sie wollen. Ich empfehle entweder Option 1 oder Option 2 . Bitte verwenden Sie NICHT verwenden Option 0 .

## Option 0

Konvertieren Sie aund bin ein Double, und Sie können die Division verwenden und Math.ceilwie Sie wollten, dass es funktioniert. Ich rate jedoch dringend von der Verwendung dieses Ansatzes ab, da eine doppelte Teilung ungenau sein kann. Weitere Informationen zur Ungenauigkeit von Doppelbetten finden Sie in dieser Frage .

int n = (int) Math.ceil((double) a / b));

##Option 1

int n = a / b + ((a % b == 0) ? 0 : 1); 

Sie tun a / bimmer Boden, wenn aund bbeide ganze Zahlen sind. Dann haben Sie eine Inline-if-Anweisung, die prüft, ob Sie anstelle des Bodens eine Decke verwenden sollen oder nicht. Also +1 oder +0, wenn es einen Rest mit der Division gibt, brauchen Sie +1. a % b == 0prüft auf den Rest.

##Option 2

Diese Option ist sehr kurz, aber für einige weniger intuitiv. Ich denke, dieser weniger intuitive Ansatz wäre schneller als der Ansatz der doppelten Teilung und des Vergleichs:
Bitte beachten Sie, dass dies nicht funktioniert b < 0.

int n = (a + b - 1) / b;

Um die Wahrscheinlichkeit eines Überlaufs zu verringern, können Sie Folgendes verwenden. Bitte beachten Sie jedoch, dass es für a = 0und nicht funktioniert b < 1.

int n = (a - 1) / b + 1;

## Erklärung hinter dem "weniger intuitiven Ansatz"

Da das Teilen von zwei Ganzzahlen in Java (und den meisten anderen Programmiersprachen) immer das Ergebnis beeinflusst. So:

int a, b;
int result = a/b (is the same as floor(a/b) )

Aber wir wollen nicht floor(a/b), aber ceil(a/b)und verwenden die Definitionen und Handlungen von Wikipedia :Geben Sie hier die Bildbeschreibung ein

Mit diesen Darstellungen der Boden- und Deckenfunktion können Sie die Beziehung sehen.

Bodenfunktion Deckenfunktion

Sie können das sehen floor(x) <= ceil(x). Wir brauchen floor(x + s) = ceil(x). Also müssen wir finden s. Wenn wir 1/2 <= s < 1davon ausgehen, dass es genau richtig ist (probieren Sie einige Zahlen aus und Sie werden sehen, dass es so ist, ich finde es selbst schwierig, dies zu beweisen). Und 1/2 <= (b-1) / b < 1so

ceil(a/b) = floor(a/b + s)
          = floor(a/b + (b-1)/b)
          = floor( (a+b-1)/b) )

Dies ist kein wirklicher Beweis, aber ich hoffe, Sie sind damit zufrieden. Wenn jemand es besser erklären kann, würde ich es auch schätzen. Vielleicht fragen Sie es bei MathOverflow .


1
Es wäre ein großer Gefallen, wenn Sie die Intuition hinter dem weniger intuitiven Ansatz erklären könnten? Ich weiß, dass dies richtig ist, ich möchte wissen, wie Sie dazu gekommen sind und wie ich mathematisch zeigen kann, dass es richtig ist. Ich habe versucht, es mathematisch zu lösen, war nicht überzeugt.
Saad Rehman Shah

Ich hoffe du bist zufrieden mit meiner Bearbeitung, ich kann es nicht besser machen, denke ich :(
martijnn2008

Ich gehe davon aus, dass Math.floor und Ceil nur für die Ganzzahldivision korrekt sind, nicht für die Langdivision, wenn die Werte in Doppel umgewandelt werden. Zähler Beispiele sind 4611686018427386880/4611686018427387137 versagt am Boden und 4611686018427386881/4611686018427386880 versagt an der Decke
Wouter

2
Klarstellung: Die Ergebnisse der beiden Unteroptionen von Option 2 sind nicht in allen Fällen identisch. Ein Wert von Null für a liefert 0 in der ersten und 1 in der zweiten (was für die meisten Anwendungen nicht die richtige Antwort ist).
Sushisource

1
Sind Sie sicher, dass Sie nicht "Allerdings beachten Sie bitte, dass es nicht für a = 0 und b < 1
funktioniert

60

157/32 ist int/int, was zu einem führt int.

Versuchen Sie es mit dem doppelten Literal - 157/32dwas bedeutet int/double, dass a double.


Sind Sie sicher, dass int / int immer zu einem int führt?! Kannst du bitte eine Quelle dafür geben?!


34

157/32ist eine Ganzzahldivision, da alle numerischen Literale Ganzzahlen sind, sofern nicht anders mit einem Suffix angegeben ( dfür double lfor long).

Die Division wird abgerundet (auf 4), bevor sie in ein Double (4.0) umgewandelt wird, das dann aufgerundet wird (auf 4.0).

Wenn Sie Variablen verwenden, können Sie dies vermeiden

double a1=157;
double a2=32;
int total = (int) Math.ceil(a1/a2);


7

Niemand hat das intuitivste erwähnt:

int x = (int) Math.round(Math.ceil((double) 157 / 32));

Diese Lösung behebt die Ungenauigkeit der doppelten Teilung.


1
Math.round kehrt lange zurück
Zulqurnain Jutt

Danke @ZulqurnainJutt, fügte eine Besetzung hinzu
IG Pascual

4

In Java wird durch Hinzufügen einer .0 ein doppeltes ...

int total = (int) Math.ceil(157.0 / 32.0);

3

Wenn zwei ganze Zahlen geteilt werden, z.

int c = (int) a / (int) b;

das Ergebnis ist ein int, dessen Wert durch ageteilt wird b, gegen Null gerundet. Da das Ergebnis bereits gerundet ist, ceil()wird nichts unternommen. Beachten Sie, dass diese Rundung nicht mit der Rundung in floor()Richtung negativer Unendlichkeit identisch ist . Also, 3/2gleich 1(und floor(1.5)gleich 1.0, aber (-3)/2gleich -1(aber floor(-1.5)gleich -2.0).

Das ist wichtig , denn wenn a/bwaren immer gleich floor(a / (double) b), dann könnte man einfach implementieren ceil()von a/bwie -( (-a) / b).

Der Vorschlag, ceil(a/b)von zu kommen

int n = (a + b - 1) / b;, was äquivalent zu a / b + (b - 1) / boder ist(a - 1) / b + 1

funktioniert, weil ceil(a/b)immer eins größer ist als floor(a/b), außer wenn a/beine ganze Zahl ist. Sie möchten es also auf die nächste ganze Zahl (oder darüber hinaus) stoßen, es sei denn, es a/bhandelt sich um eine ganze Zahl. Das Hinzufügen 1 - 1 / bwird dies tun. Bei ganzen Zahlen werden sie nicht ganz auf die nächste ganze Zahl angehoben. Für alles andere wird es.

Huch. Hoffentlich macht das Sinn. Ich bin sicher, es gibt eine mathematisch elegantere Möglichkeit, dies zu erklären.


2

Um eine Zahl von einer Ganzzahl in eine reelle Zahl umzuwandeln, können Sie auch einen Punkt hinzufügen:

int total = (int) Math.ceil(157/32.);

Und das Ergebnis von (157/32.) Wird auch real sein. ;)



1

Überprüfen Sie die folgende Lösung für Ihre Frage:

int total = (int) Math.ceil(157/32);

Hier sollten Sie Numerator mit 1.0 multiplizieren, dann gibt es Ihre Antwort.

int total = (int) Math.ceil(157*1.0/32);

0

Verwenden Sie double, um wie zu werfen

Math.ceil((double)value) oder wie

Math.ceil((double)value1/(double)value2);

0

Java bietet /standardmäßig nur eine Bodenteilung. Aber wir können die Decke in Bezug auf den Boden schreiben . Mal schauen:

yMit dem Formular kann eine beliebige Ganzzahl geschrieben werden y == q*k+r. Nach der Definition der Bodenteilung (hier floor), die abrundet r,

floor(q*k+r, k) == q  , where 0  r  k-1

und der Deckenteilung (hier ceil), die aufrundet r₁,

ceil(q*k+r₁, k) == q+1  , where 1  r  k

wo wir Ersatz r+1für r₁:

ceil(q*k+r+1, k) == q+1  , where 0  r  k-1


Dann setzen wir die erste Gleichung in die dritte ein, um zu qerhalten

ceil(q*k+r+1, k) == floor(q*k+r, k) + 1  , where 0  r  k-1

Schließlich gegeben, jede ganze Zahl , ywo y = q*k+r+1für einige q, k, r, wir haben

ceil(y, k) == floor(y-1, k) + 1

Und wir sind fertig. Hoffe das hilft.


Ich bin mir sicher, dass dies richtig ist, aber da es darum geht, dies zu klären, ist mir nicht klar, warum dies ceilals solches aus der intuitiven Definition definiert wird, insbesondere wenn wir die Obergrenze einer ganzen Zahl nehmen, dh r1 = k. Da die Randfälle das Knifflige daran sind, denke ich, dass es etwas genauer formuliert werden muss.
Luigi Plinge

@LuigiPlinge Für mich kann die Ableitung aufgrund des intrinsischen Unterschieds zwischen Boden und Decke im Zusammenhang mit dem Teilungsbetrieb nicht einfacher sein. Ich denke, Sie müssen sich nicht auf den Randfall konzentrieren - es ist eine natürliche Tatsache, wenn Sie versuchen, die Definitionen von Boden und Decke durch Aufteilen einer ganzen Zahl zu vereinheitlichen. Infolgedessen besteht der Beweis nur aus drei Schritten, und die Schlussfolgerung kann grob als "ein amortisierter Schritt zurück, dann ein absoluter Schritt vorwärts" in Erinnerung bleiben.
ShellayLee

0

Es gibt zwei Methoden, mit denen Sie Ihren doppelten Wert aufrunden können.

  1. Math.ceil
  2. Math.floor

Wenn Sie Ihre Antwort 4.90625 als 4 wünschen, sollten Sie Math.floor verwenden, und wenn Sie Ihre Antwort 4.90625 als 5 wünschen, können Sie Math.ceil verwenden

Sie können den folgenden Code dafür verwenden.

public class TestClass {

    public static void main(String[] args) {
        int floorValue = (int) Math.floor((double)157 / 32);
        int ceilValue = (int) Math.ceil((double)157 / 32);
        System.out.println("Floor: "+floorValue);
        System.out.println("Ceil: "+ceilValue);

    }

}

-3
int total = (157-1)/32 + 1

oder allgemeiner

(a-1)/b +1 

Ich denke, das funktioniert, aber Sie haben nicht wirklich erklärt, warum die Originalversion nicht funktioniert hat.
Teepeemm

" Bitte beachten Sie jedoch, dass es für a = 0 und b <1 nicht funktioniert "
IG Pascual
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.