No puedo entender por qué Python no tiene una signfunción. Tiene un absincorporado (que considero signla hermana), pero nosign .
En python 2.6 hay incluso una copysignfunción (en matemáticas ), pero no hay signo. ¿Por qué molestarse en escribir un copysign(x,y)cuando podría simplemente escribir un signy luego obtener el copysigndirectamente abs(x) * sign(y)? Lo último sería mucho más claro: x con el signo de y, mientras que con copysign debe recordar si es x con el signo de y o y con el signo de x.
Obviamente sign(x)no proporciona nada más quecmp(x,0) , pero sería mucho más legible que esto también (y para un lenguaje muy legible como python, esto habría sido una gran ventaja).
Si yo fuera un diseñador de Python, sería lo contrario: no cmpincorporado, sino a sign. Cuando lo necesite cmp(x,y), podría hacer un sign(x-y)(o, mejor aún para cosas no numéricas, solo una x> y, por supuesto, esto debería haber requerido sortedaceptar un booleano en lugar de un comparador de enteros). Esto también sería más claro: positivo cuando x>y(mientras cmpque hay que recordar la convención positiva cuando la primera es más grande , pero podría ser al revés). Por supuestocmp tiene sentido en sí mismo por otras razones (por ejemplo, al ordenar cosas no numéricas, o si desea que la clasificación sea estable, lo que no es posible usar simplemente con un valor booleano)
Entonces, la pregunta es: ¿por qué los diseñadores de Python decidieron dejar la signfunción fuera del lenguaje? ¿Por qué se molestan los diablos copysigny no su padre sign?
¿Me estoy perdiendo de algo?
EDITAR - después del comentario de Peter Hansen. Es justo que no lo haya usado, pero no dijo para qué usa Python. ¡En 7 años que uso Python, lo necesité incontables veces, y la última es la gota que colmó el vaso!
Sí, puedes pasar cmp, pero el 90% de las veces que tuve que pasar fue en un idioma como
lambda x,y: cmp(score(x),score(y))ese hubiera funcionado bien con el signo.
Finalmente, espero que esté de acuerdo en que signsería más útil que copysign, así que incluso si compré su vista, ¿por qué molestarse en definir eso en matemáticas, en lugar de firmar? ¿Cómo puede ser tan útil Copysign que Sign?
fuente

Respuestas:
EDITAR:
De hecho, había un parche que incluía
sign()en las matemáticas , pero no fue aceptado, porque no estaban de acuerdo en lo que debería devolver en todos los casos extremos (+/- 0, +/- nan, etc.)Por lo tanto, decidieron implementar solo copysign, que (aunque más detallado) se puede usar para delegar al usuario final el comportamiento deseado para casos extremos , que a veces pueden requerir la llamada
cmp(x,0).No sé por qué no está integrado, pero tengo algunas ideas.
Lo más importante,
copysignes un superconjunto design! Llamarcopysigncon x = 1 es lo mismo que unasignfunción. Entonces puedes usarlocopysigny olvidarte de él .Si te cansas de pasar dos argumentos completos, puedes implementar
signesta manera, y seguirá siendo compatible con el material IEEE mencionado por otros:En segundo lugar, generalmente cuando desea el signo de algo, simplemente termina multiplicándolo con otro valor. Y, por supuesto, eso es básicamente lo que
copysignhace.Entonces, en lugar de:
Solo puedes hacer:
Y sí, ¡me sorprende que hayas estado usando Python durante 7 años y creo que
cmppodría eliminarse y reemplazarse tan fácilmentesign! ¿Nunca ha implementado una clase con un__cmp__método? ¿Nunca ha llamadocmpy especificado una función de comparación personalizada?En resumen, me he encontrado queriendo una
signfunción también, perocopysigncon el primer argumento siendo 1 funcionará bien. No estoy de acuerdo con quesignsería más útilcopysign, ya que he demostrado que es simplemente un subconjunto de la misma funcionalidad.fuente
[int(copysign(1, zero)) for zero in (0, 0.0, -0.0)]da[1, 1, -1]. Eso debería haber sido[0, 0, 0]según en.wikipedia.org/wiki/Sign_functioncopysign(a,b)devuelve a con el signo de b - b es la entrada variable, a es el valor a normalizar con el signo de b. En este caso, el comentarista está ilustrando que copysign (1, x) como un reemplazo para el signo (x) falla, ya que devuelve 1 para x = 0, mientras que el signo (0) se evaluaría a 0.cmp()dará los resultados deseados, probablemente para casi todos los casos que a alguien le interesaría:[cmp(zero, 0) for zero in (0, 0.0, -0.0, -4, 5)]==>[0, 0, 0, -1, 1].s = sign(a) b = b * sno es equivalente ab = copysign(b, a)! No considera el signo de b. Por ejemplo, sia=b=-1el primer código devolverá 1 mientras que el segundo devuelve -1"copysign" está definido por IEEE 754 y forma parte de la especificación C99. Por eso está en Python. La función no se puede implementar en su totalidad por abs (x) * signo (y) debido a cómo se supone que debe manejar los valores de NaN.
Eso hace que copysign () sea una función más útil que sign ().
En cuanto a las razones específicas por las que el signbit (x) de IEEE no está disponible en Python estándar, no lo sé. Puedo hacer suposiciones, pero sería adivinar.
El módulo matemático en sí usa copysign (1, x) como una forma de verificar si x es negativo o no negativo. Para la mayoría de los casos, tratar con funciones matemáticas que parece más útil que tener un signo (x) que devuelve 1, 0 o -1 porque hay un caso menos a tener en cuenta. Por ejemplo, lo siguiente es del módulo matemático de Python:
Allí puede ver claramente que copysign () es una función más efectiva que una función de signo de tres valores ().
Tu escribiste:
Eso significa que no sabes que cmp () se usa para otras cosas además de los números. cmp ("This", "That") no se puede implementar con una función sign ().
Editar para recopilar mis respuestas adicionales en otro lugar :
Basas tus justificaciones en cómo a menudo se ven juntos abs () y sign (). Como la biblioteca estándar de C no contiene ningún tipo de función 'sign (x)', no sé cómo justifica sus puntos de vista. Hay un abs (int) y fabs (doble) y fabsf (flotante) y fabsl (largo) pero no se menciona el signo. Hay "copysign ()" y "signbit ()", pero solo se aplican a los números IEEE 754.
Con números complejos, ¿qué signo (-3 + 4j) volvería en Python, si se implementara? abs (-3 + 4j) devuelve 5.0. Ese es un claro ejemplo de cómo abs () se puede usar en lugares donde sign () no tiene sentido.
Supongamos que se agrega el signo (x) a Python, como complemento de abs (x). Si 'x' es una instancia de una clase definida por el usuario que implementa el método __abs __ (self), entonces abs (x) llamará a x .__ abs __ (). Para funcionar correctamente, para manejar abs (x) de la misma manera, Python tendrá que obtener un signo espacio de (x).
Esto es excesivo para una función relativamente innecesaria. Además, ¿por qué debería existir el signo (x) y no existir el negativo (x) y el no positivo (x)? Mi fragmento de la implementación del módulo matemático de Python muestra cómo se puede usar copybit (x, y) para implementar nonnegative (), lo que no puede hacer un simple signo (x).
Python debería admitir tener un mejor soporte para la función matemática IEEE 754 / C99. Eso agregaría una función signbit (x), que haría lo que quieras en el caso de flotadores. No funcionaría para enteros o números complejos, mucho menos cadenas, y no tendría el nombre que está buscando.
Usted pregunta "por qué", y la respuesta es "el signo (x) no es útil". Afirmas que es útil. Sin embargo, sus comentarios muestran que no sabe lo suficiente como para poder hacer esa afirmación, lo que significa que tendría que mostrar evidencia convincente de su necesidad. Decir que NumPy lo implementa no es lo suficientemente convincente. Debería mostrar casos de cómo se mejoraría el código existente con una función de signo.
Y eso está fuera del alcance de StackOverflow. Llévelo a una de las listas de Python.
fuente
cmp()nisign():-)Otro trazador de líneas para sign ()
Si desea que devuelva 0 para x = 0:
fuente
cmp(x, 0)es equivalentesignylambda x: cmp(x, 0)es más legible de lo que sugiere.-1 if x < 0 else 1?sign = lambda x: -1 if x < 0 else 1Es un 15% más rápido . Lo mismo consign = lambda x: x and (-1 if x < 0 else 1).Como
cmpse ha eliminado , puede obtener la misma funcionalidad conFunciona para
float,inte inclusoFraction. En el caso defloat, avisosign(float("nan"))es cero.Python no requiere que las comparaciones devuelvan un valor booleano, por lo que obligar a las comparaciones a bool () protege contra la implementación permitida, pero poco común:
fuente
Solo la respuesta correcta cumple con la definición de Wikipedia
La definición en Wikipedia dice:
Por lo tanto,
Que a todos los efectos puede simplificarse para:
Esta definición de función se ejecuta rápidamente y produce resultados correctos garantizados para 0, 0.0, -0.0, -4 y 5 (ver comentarios a otras respuestas incorrectas).
Tenga en cuenta que cero (0) no es ni positivo ni negativo .
fuente
numpy tiene una función de signo, y también le brinda una ventaja de otras funciones. Entonces:
Solo tenga cuidado de que el resultado sea numpy.float64:
Para cosas como json, esto es importante, ya que json no sabe cómo serializar los tipos numpy.float64. En ese caso, podrías hacer:
para obtener un flotador regular.
fuente
Intenta ejecutar esto, donde x es cualquier número
La coerción a bool () maneja la posibilidad de que el operador de comparación no devuelva un booleano.
fuente
Si un correcto
sign()función debería estar al menos en el módulo matemático, ya que está en numpy. Porque uno lo necesita con frecuencia para el código orientado a las matemáticas.Pero
math.copysign()también es útil de forma independiente.cmp()yobj.__cmp__()... tienen generalmente una gran importancia independientemente. No solo para el código orientado a las matemáticas. Considere comparar / ordenar tuplas, objetos de fecha, ...Los argumentos de desarrollo en http://bugs.python.org/issue1640 con respecto a la omisión de
math.sign()son extraños, porque:-NaNsign(nan) == nansin preocupaciones (comoexp(nan))sign(-0.0) == sign(0.0) == 0sin preocupaciónsign(-inf) == -1sin preocupación- como está en numpy
fuente
En Python 2,
cmp()devuelve un entero: no hay requisito de que el resultado sea -1, 0 o 1, porsign(x)lo que no es lo mismo quecmp(x,0).En Python 3,
cmp()se ha eliminado a favor de una comparación rica. Paracmp(), Python 3 sugiere esto :lo cual está bien para cmp (), pero nuevamente no se puede usar para sign () porque los operadores de comparación no necesitan devolver booleanos .
Para lidiar con esta posibilidad, los resultados de la comparación deben ser obligados a booleanos:
Esto funciona para cualquiera
typeque esté totalmente ordenado (incluidos valores especiales comoNaNo infinitos).fuente
No necesita uno, solo puede usar:
fuente
x / abs(x)lleva un poco más de tiempo que simplemente encadenarif/elsepara verificar en qué lado de 0 estáreturn (x > 0) - (x < 0)boolintTrueyFalsecomo1y0, se puede hacer absolutamente esto y conseguir o1,0o-1.def sign(x): return (x > 0) - (x < 0)no devolverá unbool, devolverá unint- si pasa0,0volveráSimplemente no lo hace.
La mejor manera de solucionar esto es:
fuente
La razón por la que el "signo" no está incluido es porque si incluyéramos todas las líneas útiles en la lista de funciones integradas, Python ya no sería fácil y práctico trabajar con ellas. Si usa esta función con tanta frecuencia, ¿por qué no la factoriza usted mismo? No es que sea remotamente difícil o incluso tedioso hacerlo.
fuente
abs()se dejara fuerasign()y aabs()menudo se usan juntos,sign()es el más útil de los dos (IMO), y ninguno es remotamente difícil o tedioso de implementar (a pesar de que es propenso a errores, vea cómo esta respuesta se equivoca: stackoverflow.com/questions/1986152/… )sign()sí mismo rara vez es útil. Lo que haces la mayoría de las veces es tomar diferentes rutas de código en función de si una variable es positiva o negativa, y en ese caso es más legible escribir la condición explícitamente.