Je ne comprends pas pourquoi Python n'a pas de sign
fonction. Il a un abs
intégré (que je considère comme sign
la sœur de), mais non sign
.
En python 2.6, il y a même une copysign
fonction (en mathématiques ), mais aucun signe. Pourquoi prendre la peine d'écrire un copysign(x,y)
alors que vous pourriez simplement écrire un sign
, puis obtenir copysign
directement le abs(x) * sign(y)
? Ce dernier serait beaucoup plus clair: x avec le signe de y, alors qu'avec copysign il faut se rappeler si c'est x avec le signe de y ou y avec le signe de x!
Évidemment, sign(x)
cela ne fournit rien de plus que cela cmp(x,0)
, mais ce serait beaucoup plus lisible que cela aussi (et pour un langage très lisible comme python, cela aurait été un gros plus).
Si j'étais un concepteur de python, j'aurais été dans l'autre sens: pas de cmp
builtin, mais a sign
. Lorsque vous en avez besoin cmp(x,y)
, vous pouvez simplement faire un sign(x-y)
(ou, encore mieux pour les choses non numériques, juste un x> y - bien sûr, cela aurait dû nécessiter l' sorted
acceptation d'un booléen au lieu d'un comparateur entier). Ce serait aussi plus clair: positif quand x>y
(alors qu'avec cmp
vous il faut se souvenir de la convention positive quand la première est plus grosse , mais ça pourrait être l'inverse). Bien sûr, cmp
cela a du sens en soi pour d'autres raisons (par exemple lors du tri de choses non numériques, ou si vous voulez que le tri soit stable, ce qui n'est pas possible en utilisant simplement un booléen)
Donc, la question est: pourquoi le ou les concepteurs Python ont-ils décidé de laisser la sign
fonction hors du langage? Pourquoi diable dérange-t-il copysign
et non pas son parent sign
?
Suis-je en train de manquer quelque chose?
EDIT - après le commentaire de Peter Hansen. Assez juste que vous ne l'avez pas utilisé, mais vous n'avez pas dit pourquoi vous utilisez python. En 7 ans que j'utilise le python, j'en ai eu besoin d'innombrables fois, et la dernière est la paille qui a cassé le dos du chameau!
Oui, vous pouvez passer le cmp, mais 90% des fois où j'ai eu besoin de le passer, c'était dans un idiome comme
lambda x,y: cmp(score(x),score(y))
ça aurait très bien fonctionné avec le signe.
Enfin, j'espère que vous conviendrez que ce sign
serait plus utile que copysign
, donc même si j'ai acheté votre point de vue, pourquoi vous soucier de définir cela en mathématiques, au lieu de signer? Comment le copysign peut-il être aussi utile que signer?
la source
Réponses:
ÉDITER:
En effet, il y avait un correctif qui était inclus
sign()
dans les mathématiques , mais il n'a pas été accepté, car ils n'étaient pas d'accord sur ce qu'il devrait retourner dans tous les cas de bord (+/- 0, +/- nan, etc.)Ils ont donc décidé de n'implémenter que le copysign, qui (bien que plus détaillé) peut être utilisé pour déléguer à l'utilisateur final le comportement souhaité pour les cas limites - ce qui peut parfois nécessiter l'appel à
cmp(x,0)
.Je ne sais pas pourquoi ce n'est pas intégré, mais j'ai quelques réflexions.
Plus important encore,
copysign
c'est un surensemble design
! Appelercopysign
avec x = 1 équivaut à unesign
fonction. Vous pouvez donc simplement l'utilisercopysign
et l' oublier .Si vous en avez marre de passer deux arguments entiers, vous pouvez l'implémenter de
sign
cette façon, et il sera toujours compatible avec les trucs IEEE mentionnés par d'autres:Deuxièmement, généralement lorsque vous voulez le signe de quelque chose, vous finissez par le multiplier par une autre valeur. Et bien sûr, c'est essentiellement ce qui
copysign
fait.Donc, au lieu de:
Vous pouvez simplement faire:
Et oui, je suis surpris que vous utilisiez Python depuis 7 ans et pensez que cela
cmp
pourrait être si facilement supprimé et remplacé parsign
! Vous n'avez jamais implémenté une classe avec une__cmp__
méthode? Vous n'avez jamais appelécmp
et spécifié une fonction de comparaison personnalisée?En résumé, je me suis retrouvé à vouloir une
sign
fonction aussi, maiscopysign
avec le premier argument étant 1 fonctionnera très bien. Je ne suis pas d'accord que cesign
serait plus utile quecopysign
, car j'ai montré qu'il ne s'agit que d'un sous-ensemble de la même fonctionnalité.la source
[int(copysign(1, zero)) for zero in (0, 0.0, -0.0)]
donne[1, 1, -1]
. Cela aurait dû être[0, 0, 0]
selon en.wikipedia.org/wiki/Sign_functioncopysign(a,b)
renvoie a avec le signe de b - b est l'entrée variable, a est la valeur à normaliser avec le signe de b. Dans ce cas, le commentateur illustre que le copysign (1, x) en remplacement du signe (x) échoue, car il renvoie 1 pour x = 0, tandis que le signe (0) serait évalué à 0.cmp()
donnera les résultats souhaités, probablement pour presque tous les cas, n'importe qui se souciera de:[cmp(zero, 0) for zero in (0, 0.0, -0.0, -4, 5)]
==>[0, 0, 0, -1, 1]
.s = sign(a) b = b * s
n'est pas équivalent àb = copysign(b, a)
! Il ne considère pas le signe de b. Par exemple, sia=b=-1
le premier code renvoie 1 tandis que le second renvoie -1"copysign" est défini par IEEE 754 et fait partie de la spécification C99. C'est pourquoi c'est en Python. La fonction ne peut pas être implémentée dans son intégralité par le signe abs (x) * (y) en raison de la façon dont elle est censée gérer les valeurs NaN.
Cela fait de copysign () une fonction plus utile que sign ().
Quant aux raisons spécifiques pour lesquelles le signbit (x) de l'IEEE n'est pas disponible en Python standard, je ne sais pas. Je peux faire des hypothèses, mais ce serait deviner.
Le module mathématique lui-même utilise copysign (1, x) comme moyen de vérifier si x est négatif ou non négatif. Pour la plupart des cas, traiter des fonctions mathématiques semble plus utile que d'avoir un signe (x) qui renvoie 1, 0 ou -1 car il y a un cas de moins à considérer. Par exemple, ce qui suit provient du module mathématique de Python:
Là, vous pouvez clairement voir que copysign () est une fonction plus efficace qu'une fonction de signe () à trois valeurs.
Tu as écrit:
Cela signifie que vous ne savez pas que cmp () est utilisé pour des choses autres que les nombres. cmp ("This", "That") ne peut pas être implémenté avec une fonction sign ().
Modifier pour rassembler mes réponses supplémentaires ailleurs :
Vous fondez vos justifications sur la façon dont abs () et sign () sont souvent vus ensemble. Comme la bibliothèque standard C ne contient aucune fonction "signe (x)", je ne sais pas comment vous justifiez vos vues. Il y a un abs (int) et fabs (double) et fabsf (float) et fabsl (long) mais aucune mention de signe. Il existe "copysign ()" et "signbit ()" mais ceux-ci ne s'appliquent qu'aux numéros IEEE 754.
Avec des nombres complexes, que signifierait (-3 + 4j) en Python, devait-il être implémenté? abs (-3 + 4j) renvoie 5,0. C'est un exemple clair de la façon dont abs () peut être utilisé dans des endroits où sign () n'a aucun sens.
Supposons que le signe (x) ait été ajouté à Python, en complément de abs (x). Si 'x' est une instance d'une classe définie par l'utilisateur qui implémente la méthode __abs __ (self) alors abs (x) appellera x .__ abs __ (). Pour fonctionner correctement, pour gérer abs (x) de la même manière, Python devra gagner un emplacement de signe (x).
Ceci est excessif pour une fonction relativement inutile. En outre, pourquoi le signe (x) devrait-il exister et le non négatif (x) et le non positif (x) n'existeraient pas? Mon extrait de l'implémentation du module mathématique de Python montre comment copybit (x, y) peut être utilisé pour implémenter nonnegative (), ce qu'un simple signe (x) ne peut pas faire.
Python devrait prendre en charge une meilleure prise en charge de la fonction mathématique IEEE 754 / C99. Cela ajouterait une fonction signbit (x), qui ferait ce que vous voulez dans le cas des flottants. Cela ne fonctionnerait pas pour les nombres entiers ou complexes, encore moins pour les chaînes, et il n'aurait pas le nom que vous recherchez.
Vous demandez "pourquoi", et la réponse est "le signe (x) n'est pas utile". Vous affirmez que c'est utile. Pourtant, vos commentaires montrent que vous n'en savez pas assez pour être en mesure de faire cette affirmation, ce qui signifie que vous devrez fournir des preuves convaincantes de son besoin. Dire que NumPy l'implémente n'est pas assez convaincant. Vous auriez besoin de montrer des cas d'amélioration du code existant avec une fonction de signe.
Et qu'il sort du cadre de StackOverflow. Prenez-le à la place dans l'une des listes Python.
la source
cmp()
nisign()
:-)Un autre liner pour signe ()
Si vous voulez qu'il renvoie 0 pour x = 0:
la source
cmp(x, 0)
c'est équivalentsign
etlambda x: cmp(x, 0)
plus lisible que ce que vous suggérez.-1 if x < 0 else 1
?sign = lambda x: -1 if x < 0 else 1
est 15% plus rapide . Même chose avecsign = lambda x: x and (-1 if x < 0 else 1)
.Depuis qu'il
cmp
a été supprimé , vous pouvez obtenir les mêmes fonctionnalités avecCela fonctionne pour
float
,int
et mêmeFraction
. Dans le cas defloat
, l'avissign(float("nan"))
est nul.Python n'exige pas que les comparaisons renvoient un booléen, et donc contraindre les comparaisons à bool () protège contre une implémentation autorisée, mais rare:
la source
Seule bonne réponse conforme à la définition de Wikipedia
La définition sur Wikipédia lit comme suit:
Par conséquent,
Qui, à toutes fins utiles, peut être simplifié pour:
Cette définition de fonction s'exécute rapidement et donne des résultats corrects garantis pour 0, 0.0, -0.0, -4 et 5 (voir les commentaires des autres réponses incorrectes).
Notez que zéro (0) n'est ni positif ni négatif .
la source
numpy a une fonction de signe, et vous donne également un bonus d'autres fonctions. Alors:
Faites juste attention à ce que le résultat soit un numpy.float64:
Pour des choses comme json, cela importe, car json ne sait pas comment sérialiser les types numpy.float64. Dans ce cas, vous pourriez faire:
pour obtenir un flotteur régulier.
la source
Essayez d'exécuter ceci, où x est un nombre
La coercition à bool () gère la possibilité que l'opérateur de comparaison ne retourne pas de booléen.
la source
Oui, une
sign()
fonction correcte devrait être au moins dans le module mathématique - comme dans numpy. Parce qu'on en a souvent besoin pour du code orienté mathématique.Mais
math.copysign()
est également utile indépendamment.cmp()
etobj.__cmp__()
... ont généralement une grande importance indépendamment. Pas seulement pour le code orienté mathématiques. Pensez à comparer / trier les tuples, les objets de date, ...Les arguments de développement sur http://bugs.python.org/issue1640 concernant l'omission de
math.sign()
sont étranges, car:-NaN
sign(nan) == nan
sans souci (commeexp(nan)
)sign(-0.0) == sign(0.0) == 0
sans soucisign(-inf) == -1
sans souci- comme c'est en numpy
la source
En Python 2,
cmp()
renvoie un entier: il n'est pas nécessaire que le résultat soit -1, 0 ou 1, cesign(x)
n'est donc pas la même chose quecmp(x,0)
.En Python 3,
cmp()
a été supprimé au profit d'une comparaison riche. Pourcmp()
, Python 3 suggère ceci :ce qui est bien pour cmp (), mais encore une fois ne peut pas être utilisé pour sign () car les opérateurs de comparaison n'ont pas besoin de renvoyer de booléens .
Pour faire face à cette possibilité, les résultats de la comparaison doivent être contraints aux booléens:
Cela fonctionne pour tout
type
ce qui est totalement ordonné (y compris les valeurs spéciales commeNaN
ou infinis).la source
Vous n'en avez pas besoin, vous pouvez simplement utiliser:
la source
x / abs(x)
if/else
return (x > 0) - (x < 0)
bool
int
True
etFalse
que1
et0
, vous pouvez absolument faire cela et soit1
,0
ou-1
.def sign(x): return (x > 0) - (x < 0)
ne reviendra pas unbool
, ça va revenir unint
- si vous passez0
vous obtenez en0
arrièreCe n'est pas le cas.
La meilleure façon de résoudre ce problème est:
la source
La raison pour laquelle "signe" n'est pas inclus est que si nous incluions toutes les lignes utiles dans la liste des fonctions intégrées, Python ne serait plus facile et pratique à utiliser. Si vous utilisez cette fonction si souvent, alors pourquoi ne pas la prendre en compte vous-même? Ce n'est pas comme si c'était à distance difficile ou même fastidieux de le faire.
la source
abs()
était également omis.sign()
etabs()
sont souvent utilisés ensemble,sign()
est le plus utile des deux (IMO), et aucun n'est à distance difficile ou fastidieux à mettre en œuvre (même s'il est sujet aux erreurs, voyez comment cette réponse se trompe: stackoverflow.com/questions/1986152/… )sign()
lui-même est rarement utile. La plupart du temps, vous prenez des chemins de code différents selon que la variable est positive ou négative, et dans ce cas, il est plus lisible d'écrire la condition explicitement.