No puedo entender por qué Python no tiene una sign
función. Tiene un abs
incorporado (que considero sign
la hermana), pero nosign
.
En python 2.6 hay incluso una copysign
función (en matemáticas ), pero no hay signo. ¿Por qué molestarse en escribir un copysign(x,y)
cuando podría simplemente escribir un sign
y luego obtener el copysign
directamente 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 cmp
incorporado, 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 sorted
aceptar un booleano en lugar de un comparador de enteros). Esto también sería más claro: positivo cuando x>y
(mientras cmp
que 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 sign
función fuera del lenguaje? ¿Por qué se molestan los diablos copysign
y 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 sign
serí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,
copysign
es un superconjunto design
! Llamarcopysign
con x = 1 es lo mismo que unasign
función. Entonces puedes usarlocopysign
y olvidarte de él .Si te cansas de pasar dos argumentos completos, puedes implementar
sign
esta 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
copysign
hace.Entonces, en lugar de:
Solo puedes hacer:
Y sí, ¡me sorprende que hayas estado usando Python durante 7 años y creo que
cmp
podría eliminarse y reemplazarse tan fácilmentesign
! ¿Nunca ha implementado una clase con un__cmp__
método? ¿Nunca ha llamadocmp
y especificado una función de comparación personalizada?En resumen, me he encontrado queriendo una
sign
función también, perocopysign
con el primer argumento siendo 1 funcionará bien. No estoy de acuerdo con quesign
serí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 * s
no es equivalente ab = copysign(b, a)
! No considera el signo de b. Por ejemplo, sia=b=-1
el 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 equivalentesign
ylambda 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 1
Es un 15% más rápido . Lo mismo consign = lambda x: x and (-1 if x < 0 else 1)
.Como
cmp
se ha eliminado , puede obtener la misma funcionalidad conFunciona para
float
,int
e 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:-NaN
sign(nan) == nan
sin preocupaciones (comoexp(nan)
)sign(-0.0) == sign(0.0) == 0
sin preocupaciónsign(-inf) == -1
sin 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
type
que esté totalmente ordenado (incluidos valores especiales comoNaN
o infinitos).fuente
No necesita uno, solo puede usar:
fuente
x / abs(x)
lleva un poco más de tiempo que simplemente encadenarif/else
para verificar en qué lado de 0 estáreturn (x > 0) - (x < 0)
bool
int
True
yFalse
como1
y0
, se puede hacer absolutamente esto y conseguir o1
,0
o-1
.def sign(x): return (x > 0) - (x < 0)
no devolverá unbool
, devolverá unint
- si pasa0
,0
volverá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.