1149 votes

Comment effectuer une division entière, et obtenir séparément le reste, en JavaScript ?

En JavaScript comment puis-je obtenir :

  1. Le nombre entier de fois qu'un nombre entier donné entre dans un autre ?
  2. Le reste ?

1545voto

Mark Elliot Points 31871

Pour un certain nombre y et un diviseur x calculer le quotient ( quotient ) et le reste ( remainder ) comme :

var quotient = Math.floor(y/x);
var remainder = y % x;

96 votes

% fonctionne sur les flottants en JavaScript (ce qui diffère de nombreux autres langages), ce qui n'est peut-être pas souhaité : 3.5 % 2 évalue à 1,5. Assurez-vous de manipuler (parseInt, floor, etc.) comme il se doit.

19 votes

La partie intégrale de -4,5 en mathématiques est -5, car -5 est le "plus grand nombre intégral possible qui est encore inférieur à -4,5".

21 votes

Cependant, quelle que soit votre décision concernant les nombres négatifs, elle doit être cohérente pour le quotient et le reste. Utilisation de floor y % ensemble n'est pas cohérent de cette manière. Soit vous utilisez trunc au lieu de floor (ce qui autorise les restes négatifs) ou utiliser la soustraction pour obtenir le reste ( rem = y - div * x ).

442voto

user113716 Points 143363

Je ne suis pas un expert en opérateurs binaires, mais voici une autre façon d'obtenir le nombre entier :

var num = ~~(a / b);

Cela fonctionnera aussi correctement pour les nombres négatifs, alors que Math.floor() va tourner dans la mauvaise direction.

Cela semble correct également :

var num = (a / b) >> 0;

99 votes

Un autre, dont je viens de passer les 20 dernières minutes à essayer de comprendre l'utilité, est apparemment a/b | 0

23 votes

@user113716 @BlueRaja Les opérations par bit n'ont de sens que pour les types d'entiers et JS (bien sûr) le sait. ~~int , int | 0 y int >> 0 ne modifie pas l'argument initial, mais fait en sorte que l'interpréteur passe la partie intégrale à l'opérateur.

3 votes

Au cas où quelqu'un se demanderait lequel est le plus rapide : jsperf.com/integer-division-math-floor-a-b-vs-a-b (Les résultats des spoilers ne sont pas concluants).

269voto

KalEl Points 1846

J'ai fait quelques tests de vitesse sur Firefox.

-100/3             // -33.33..., 0.3663 millisec
Math.floor(-100/3) // -34,       0.5016 millisec
~~(-100/3)         // -33,       0.3619 millisec
(-100/3>>0)        // -33,       0.3632 millisec
(-100/3|0)         // -33,       0.3856 millisec
(-100-(-100%3))/3  // -33,       0.3591 millisec

/* a=-100, b=3 */
a/b                // -33.33..., 0.4863 millisec
Math.floor(a/b)    // -34,       0.6019 millisec
~~(a/b)            // -33,       0.5148 millisec
(a/b>>0)           // -33,       0.5048 millisec
(a/b|0)            // -33,       0.5078 millisec
(a-(a%b))/b        // -33,       0.6649 millisec

Les résultats ci-dessus sont basés sur 10 millions d'essais pour chacun.

Conclusion : Utilisez (a/b>>0) (ou (~~(a/b)) ou (a/b|0) ) pour obtenir un gain d'efficacité d'environ 20 %. Gardez également à l'esprit qu'ils sont tous incompatibles avec Math.floor quand a/b<0 && a%b!=0 .

2 votes

Je trouve que Math.floor() a des performances plus stables que les autres. Il y a moins de hauts et de bas.

80 votes

Notez que l'optimisation de la division d'entiers pour la vitesse n'a de sens que si vous la faites beaucoup . Dans tous les autres cas, je vous recommande de choisir le plus simple (celui qui vous semble le plus simple à vous et à vos collègues).

10 votes

@m01 tout à fait d'accord - il y a beaucoup trop de concentration sur ce genre de choses en ligne.

216voto

Oriol Points 20803

ES6 introduit le nouveau Math.trunc méthode. Cela permet de fixer La réponse de @MarkElliot pour que cela fonctionne aussi pour les nombres négatifs :

var div = Math.trunc(y/x);
var rem = y % x;

Notez que Math ont l'avantage, par rapport aux opérateurs binaires, de fonctionner avec des nombres supérieurs à 2. 31 .

0 votes

Var y =18014398509481984 ; var x= 5 ; div = ? - bug ?

5 votes

@4esn0k Ce n'est pas un bug. Votre nombre a trop de chiffres, vous ne pouvez pas avoir autant de précision dans un nombre IEEE 754 au format binaire 64 bits. Par exemple, 18014398509481984 == 18014398509481985 .

0 votes

18014398509481984 == 2**54, et j'ai spécialement utilisé ce nombre, car il est représenté exactement au format binaire64. et la réponse est représentée exactement aussi

35voto

gammax Points 129
var remainder = x % y;
return (x - remainder) / y;

1 votes

Cette version échoue malheureusement au test lorsque x = -100 car elle renvoie -34 au lieu de -33.

1 votes

Qu'en est-il de "var x = 0.3 ; var y = 0.01 ;" ? (merci à github.com/JuliaLang/julia/issues/4156#issuecomment-23324163 )

0 votes

En fait, @Samuel, avec des valeurs négatives, cette méthode renvoie des résultats corrects, ou du moins elle renvoie les mêmes valeurs que la méthode qui utilise Math.trunc :). J'ai vérifié avec 100,3 ; -100,3 ; 100,-3 et -100,-3. Bien sûr, beaucoup de temps s'est écoulé depuis votre commentaire et les choses changent.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X