web-dev-qa-db-fra.com

Tour avec division entière

Il y a une manière simple et pythonique d'arrondir au nombre entier le plus proche sans utiliser de point flottant? Je voudrais faire ce qui suit mais avec des arithmétiques entier:

skip = int(round(1.0 * total / surplus))

==============

@John: Le point flottant n'est pas reproductible à travers les plates-formes. Si vous souhaitez que votre code passe des tests sur différentes plates-formes, vous devez éviter le point flottant (ou ajouter des trucs hacky espilon à vos tests et espérons que cela fonctionne). Ce qui précède peut être suffisamment simple que ce serait la même chose sur la plupart des plates-formes, mais je préfère ne pas faire cette détermination car il est plus facile d'éviter tout point flottant. Comment est-ce "pas dans l'esprit de Python"?

24
gaefan

Vous pouvez le faire tout simplement:

(n + d // 2) // d, où n est le dividende et d est le diviseur.

Alternatives comme (((n << 1) // d) + 1) >> 1 ou l'équivalent (((n * 2) // d) + 1) // 2 Peut être plus lent dans les CPPHons récents, où un int est mis en œuvre comme l'ancien long.

La méthode simple contient 3 accès variables, 1 charge constante et 3 opérations entier. Les méthodes compliquées font 2 accès variables, 3 charges constantes et 4 opérations entier. Les opérations entière devraient prendre du temps, ce qui dépend de la taille des chiffres concernés. Les accès variables des locaux de fonction n'impliquent pas les "recherches".

Si vous êtes vraiment désespéré à la vitesse, faites des repères. Sinon, embrasse.

36
John Machin
skip = (((total << 1) // surplus) + 1) >> 1

Les choses déplacées laissées par un bit se multiplient efficacement par deux, les choses changeantes à un bit se divise par deux arrondies. L'ajout d'un au milieu en fait de sorte que "arrondi" soit effectivement arrondie si le résultat aurait été supérieur à une partie décimale .5.

C'est fondamentalement la même chose que si vous avez écrit ...

skip = int((1.0*total/surplus) + 0.5)

sauf avec tout ce qui est multiplié par 2, puis divisé ultérieurement par 2, ce qui est quelque chose que vous pouvez faire avec arithmétique entier (puisque les changements de bits ne nécessitent pas de point flottant).

6
Amber

Inspiré par réponse de Zhmyh réponse, qui est

q, r = divmod(total, surplus)
skip = q + int(bool(r)) # rounds to next greater integer (always ceiling)

, J'ai trouvé la solution suivante:

q, r = divmod(total, surplus) 
skip = q + int(2 * r >= surplus) # rounds to nearest integer (floor or ceiling)

Depuis que l'OP a demandé l'arrondi au le nombre entier le plus proche , la solution de ZHMHS est en fait légèrement incorrecte, car elle se termine toujours sur le suivant Nombre entier, tandis que ma solution fonctionne comme demandé.

(Si vous sentez que ma réponse devrait mieux avoir été une modification ou un commentaire sur la réponse de Zhmh, laissez-moi indiquer que ma modification suggérée pour cela a été rejetée, car elle devrait mieux avoir été un commentaire, mais je n'ai pas assez de réputation encore pour commenter

Si vous vous demandez comment divmod est défini: selon son Documentation

Pour les entiers, le résultat est le même que (a // b, a % b).

Nous nous tenons donc avec des arithmétiques entier, comme demandé par l'OP.

6
Daniel K

Encore une autre façon amusante:

q, r = divmod(total, surplus)
skip = q + int(bool(r))
2
rmnff

Prenez simplement soin de la règle de l'arrondissement avant de jamais diviser. Pour la demi-up la plus simple:

if total % surplus < surplus / 2:
    return total / surplus
else:
    return (total / surplus) + 1

Tweak un peu si vous avez besoin de faire une bonne ronde au-dessus.

0
hobbs