Bien que Python soit un langage massivement utilisé par la communauté scientifique, la lib standard ne contient pas de fonction aussi simple que sign()
. Et on voit ça et là des libs qui contiennent quelque chose comme ça:
def sign(x): if x > 0: return 1 if x == 0: return 0 return -1 >>> sign(3) 1 >>> sign(-3) -1 >>> sign(0) 0 |
Comme d’autres de choix étonnants dans l’architecture de Python, il y a une raison raisonnablement raisonnable : il n’existe aucun standard sur ce que doit faire une telle fonction dans les cas ambigües.
En effet, que doit faire la fonction avec NaN
? Avec un complexe ?
Il y a eu un débat sur ce qu’il faut faire dans ce cas, et un consensus n’a PAS été trouvé.
Par contre, il existe un standard international définissant une autre opération : celle de copier un signe. Elle a donc été implémentée :
>>> from math import copysign >>> copysign(10, -3) -10.0 >>> copysign(10, 22) 10.0 >>> copysign(10, float('-NaN')) -10 >>> copysign(10, -2j) Traceback (most recent call last): File "<ipython-input-13-ece93d1317dc>", line 1, in <module> copysign(10, -2j) TypeError: can't convert complex to float |
Copier le signe n’est pas la même chose que de retourner quelque chose selon le signe, et donc sémantiquement, choisir quoi retourner était plus facile. Comme la plupart du temps, on veut récupérer -1
ou 1
pour le multiplier avec quelque chose et justement copier le signe, cela résolvait pas mal de problèmes.
Mais même dans le rare cas où on a besoin du résultat que renverrait sign()
, il est très facile à obtenir en une ligne :
>>> mon_nombre = 3 >>> mon_nombre and copysign(1, mon_nombre) 1.0 >>> mon_nombre = -3 >>> mon_nombre and copysign(1, mon_nombre) -1.0 >>> mon_nombre = 0 >>> mon_nombre and copysign(1, mon_nombre) 0 |
Et pour ce cas de figure, les retours sur des valeurs ambigües sont laissés à la charge du codeur.
P.S: je sais qu’il y a des exemples sur le net montrant cmp(0, mon_nombre)
pour obtenir la même fonctionnalité. Sachez que cmp
a été retirée de Python 3, donc faites attention si vous l’utilisez.
Quitte à créer soi-même une fonction avec un `and`, je préfère un
qui est plus lisible je trouve qu’une fonction `copysign` dont le comportement peut sembler flou au premier abord.
@entwanne: et ça sera probablement plus rapide à l’éxécution en plus, puisqu’il y a une appel en moins. Copysign reste néanmoins idéal pour le cas le plus courant où on souhaite faire la multiplication derrière.
@entwanne: Jolie structure, très astucieuse j’aime beaucoup ! Je la garde sous le coude même si elle ne présente pas l’avantage de pouvoir prendre des nombres complexes comme copysign.
Coucou,
À quoi sert le “x and” alors??
def sign(x):
return (-1,1)[x>0]
Oups…
Désolé pour le zéro… :-D
return x / abs(x or 1)
Surement un poil plus lent que la méthode à entwanne, mais plus rapide que celle de Sam :)
Les scientifiques, comme très souvent, utilisent numpy :
Ne me demandez pas la logique pour les complexes, la doc n’en parle pas : http://docs.scipy.org/doc/numpy/reference/generated/numpy.sign.html
@poulpe : pas mal, ça évite malicieusement la division par zéro.
Pour info, voilà la logique du signe des complexes dans numpy : https://github.com/numpy/numpy/issues/3621