Java arrondi à un entier en utilisant Math.ceil

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

Pourquoi revient-il toujours 4? 157/32 = 4.90625, J'ai besoin d'arrondir, j'ai regardé autour de moi et cela semble être la bonne méthode.

J'ai essayé en totaltant que doubletype, mais obtenez 4.0.

Qu'est-ce que je fais mal?

à M
la source

Réponses:

188

Vous faites 157/32ce qui divise deux entiers l'un avec l'autre, ce qui aboutit toujours à un entier arrondi vers le bas. Par conséquent, le (int) Math.ceil(...)ne fait rien. Il existe trois solutions possibles pour réaliser ce que vous voulez. Je recommande d' utiliser l' option 1 ou l' option 2 . Veuillez NE PAS utiliser l' option 0 .

## Option 0

Convertissez aet ben un double, et vous pouvez utiliser la division et Math.ceilcomme vous le souhaitez. Cependant, je déconseille fortement l'utilisation de cette approche, car la double division peut être imprécise. Pour en savoir plus sur l'imprécision des doubles, consultez cette question .

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

##Option 1

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

Vous faites a / bavec toujours floor si aet bsont tous les deux des entiers. Ensuite, vous avez une instruction if en ligne qui vérifie si vous devez ou non plafonner au lieu de floor. Donc +1 ou +0, s'il y a un reste avec la division, vous avez besoin de +1. a % b == 0vérifie le reste.

##Option 2

Cette option est très courte, mais peut-être pour certains moins intuitive. Je pense que cette approche moins intuitive serait plus rapide que l'approche de double division et comparaison:
veuillez noter que cela ne fonctionne pas pour b < 0.

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

Pour réduire les risques de débordement, vous pouvez utiliser ce qui suit. Cependant, veuillez noter que cela ne fonctionne pas pour a = 0et b < 1.

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

## Explication derrière "l'approche moins intuitive"

Depuis la division de deux entiers en Java (et la plupart des autres langages de programmation), le résultat sera toujours plancher. Alors:

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

Mais nous ne voulons pas floor(a/b), mais ceil(a/b), et en utilisant les définitions et les graphiques de Wikipedia :entrez la description de l'image ici

Avec ces graphiques de la fonction du sol et du plafond, vous pouvez voir la relation.

Fonction de plancher Fonction Ceil

Vous pouvez le voir floor(x) <= ceil(x). Nous avons besoin floor(x + s) = ceil(x). Nous devons donc trouver s. Si nous supposons que 1/2 <= s < 1ce sera juste (essayez quelques chiffres et vous verrez que c'est le cas, j'ai moi-même du mal à le prouver). Et 1/2 <= (b-1) / b < 1donc

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

Ce n'est pas une vraie preuve, mais j'espère que vous en êtes satisfait. Si quelqu'un peut mieux l'expliquer, je l'apprécierais aussi. Demandez-le peut-être sur MathOverflow .

martijnn2008
la source
1
Ce sera une grande faveur si vous pouviez expliquer l'intuition derrière l'approche moins intuitive? Je sais que c'est correct, je veux savoir comment vous y êtes arrivé et comment puis-je démontrer mathématiquement que c'est correct. J'ai essayé de le résoudre mathématiquement, je n'étais pas convaincu.
Saad Rehman Shah
J'espère que vous êtes satisfait de mon montage, je ne peux pas faire mieux je pense :(
martijnn2008
Je suppose que Math.floor et ceil ne sont corrects que pour la division entière et non pour la division longue lorsque les valeurs sont converties en doubles. Les exemples de compteurs sont 4611686018427386880/4611686018427387137 échoue au sol et 4611686018427386881/4611686018427386880 échoue au plafond
Wouter
2
Un point de clarification: les résultats des deux sous-options de l'option 2 ne sont pas identiques dans tous les cas. Une valeur de zéro pour a fournira 0 dans le premier et 1 dans le second (ce qui n'est pas la bonne réponse pour la plupart des applications).
Sushisource
1
Etes-vous sûr de ne pas vouloir dire "Cependant, veuillez noter que cela ne fonctionne pas pour a = 0 et b < 1"
dantiston
60

157/32 est int/int, ce qui entraîne un int.

Essayez d'utiliser le double littéral - 157/32d, ce int/doublequi donne un double.

Bozho
la source
Êtes-vous sûr que int / int donnera toujours un int?! pouvez-vous s'il vous plaît donner la source à cela?!
34

157/32est une division entière car tous les littéraux numériques sont des entiers sauf indication contraire avec un suffixe ( dpour double lpour long)

la division est arrondie vers le bas (à 4) avant d'être convertie en un double (4.0) qui est ensuite arrondi (à 4.0)

si vous utilisez une variable, vous pouvez éviter cela

double a1=157;
double a2=32;
int total = (int) Math.ceil(a1/a2);
monstre à cliquet
la source
26
int total = (int) Math.ceil((double)157/32);
Phoebus
la source
7

Personne n'a mentionné le plus intuitif:

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

Cette solution corrige l' imprécision de la double division.

IG Pascual
la source
1
Math.round retourne long
Zulqurnain Jutt
Merci @ZulqurnainJutt, a ajouté un casting
IG Pascual
4

En Java, l'ajout d'un .0 en fera un double ...

int total = (int) Math.ceil(157.0 / 32.0);
Scott Higgins
la source
3

Lors de la division de deux entiers, par exemple,

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

le résultat est un int, dont la valeur est adivisée par b, arrondie vers zéro. Parce que le résultat est déjà arrondi, ceil()ne fait rien. Notez que cet arrondi n'est pas le même que floor(), qui arrondit à l'infini négatif. Donc, 3/2égal 1(et floor(1.5)égal 1.0, mais (-3)/2égal -1(mais floor(-1.5)égal -2.0).

Ceci est important parce que si a/btoujours les mêmes que floor(a / (double) b), vous pourriez tout mettre en œuvre ceil()des a/bcomme -( (-a) / b).

La suggestion d'obtenir ceil(a/b)de

int n = (a + b - 1) / b;, ce qui équivaut à a / b + (b - 1) / b, ou(a - 1) / b + 1

fonctionne parce que ceil(a/b)est toujours un supérieur à floor(a/b), sauf quand a/best un nombre entier. Donc, vous voulez le faire passer (ou dépasser) le nombre entier suivant, sauf s'il a/bs'agit d'un nombre entier. L'ajout 1 - 1 / bfera cela. Pour les nombres entiers, cela ne les poussera pas tout à fait au nombre entier suivant. Pour tout le reste, ce sera le cas.

Yikes. J'espère que cela a du sens. Je suis sûr qu'il existe une manière plus élégante mathématiquement de l'expliquer.

jorgenman
la source
2

Aussi pour convertir un nombre entier en nombre réel, vous pouvez ajouter un point:

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

Et le résultat de (157/32.) Sera réel aussi. ;)

Vitaliy Borisok
la source
2
int total = (int) Math.ceil( (double)157/ (double) 32);
pierres333
la source
1

Vérifiez la solution ci-dessous pour votre question:

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

Ici, vous devez multiplier Numérateur par 1.0, puis il donnera votre réponse.

int total = (int) Math.ceil(157*1.0/32);
Inconnue
la source
0

Utilisez double pour lancer comme

Math.ceil((double)value) ou comme

Math.ceil((double)value1/(double)value2);
Bhupinder
la source
0

Java fournit uniquement la division /par étage par défaut. Mais nous pouvons écrire un plafond en termes de plancher . Voyons voir:

Tout entier ypeut être écrit avec le formulaire y == q*k+r. Selon la définition de la division de plancher (ici floor) qui arrondit r,

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

et de division de plafond (ici ceil) qui arrondit r₁,

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

où l' on peut remplacer r+1par r₁:

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


Ensuite, nous substituons la première équation à la troisième pour qobtenir

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

Enfin, étant donné tout entier yy = q*k+r+1pour certains q, k, r, nous avons

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

Et nous avons terminé. J'espère que cela t'aides.

ShellayLee
la source
Je suis sûr que c'est correct, mais comme le but de ceci est de clarifier, je ne sais pas pourquoi ceilest défini comme tel à partir de la définition intuitive, en particulier lorsque nous prenons le ceil d'un entier, c'est-à-dire r1 = k. Étant donné que les cas extrêmes sont ce qui est délicat à ce sujet, je pense qu'il faut le préciser un peu plus.
Luigi Plinge
@LuigiPlinge Pour moi, la dérivation ne peut pas être plus simple en raison de la différence intrinsèque entre le plancher et le plafond dans le contexte de l'opération de division. Je pense que vous n'avez pas besoin de vous concentrer sur le cas du bord - c'est un fait naturel lorsque vous essayez d'unifier les définitions de plancher et de plafond en décomposant un entier. En conséquence, la preuve n'est que de trois étapes, et la conclusion peut être grossièrement rappelée comme "un pas en arrière amorti, puis un pas en avant absolu".
ShellayLee
0

Il existe deux méthodes par lesquelles vous pouvez arrondir votre double valeur.

  1. Math.ceil
  2. Math.floor

Si vous voulez que votre réponse 4.90625 soit 4, vous devez utiliser Math.floor et si vous voulez que votre réponse 4.90625 soit 5, vous pouvez utiliser Math.ceil

Vous pouvez vous référer au code suivant pour cela.

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);

    }

}
Deepak Kumbhar
la source
-3
int total = (157-1)/32 + 1

ou plus général

(a-1)/b +1 
oldcolder
la source
Je pense que cela fonctionne, mais vous n'avez pas vraiment expliqué pourquoi la version originale ne fonctionnait pas.
Teepeemm
" Cependant, veuillez noter que cela ne fonctionne pas pour a = 0 et b <1 "
IG Pascual