Não consigo entender por que o Python não tem uma sign
função. Ele tem um abs
builtin (que eu considero sign
a irmã de), mas nãosign
.
No python 2.6 há até uma copysign
função (em matemática ), mas nenhum sinal. Por que se preocupar em escrever um copysign(x,y)
quando você pode simplesmente escrever um sign
e depois obter o copysign
diretamente abs(x) * sign(y)
? O último seria muito mais claro: x com o sinal de y, enquanto no copysign você deve se lembrar se é x com o sinal de y ou y com o sinal de x!
Obviamente sign(x)
, não fornece nada além disso cmp(x,0)
, mas seria muito mais legível que isso também (e para uma linguagem muito legível como python, isso seria uma grande vantagem).
Se eu fosse um designer de python, seria o contrário: não cmp
embutido, mas a sign
. Quando você precisar cmp(x,y)
, você pode simplesmente fazer um sign(x-y)
(ou, melhor ainda, para coisas não numéricas, apenas um x> y - é claro que isso deveria exigir a sorted
aceitação de um booleano em vez de um comparador inteiro). Isso também ficaria mais claro: positivo quando x>y
(considerando que cmp
você deve se lembrar da convenção positiva quando o primeiro for maior , mas pode ser o contrário). É claro que cmp
faz sentido por outras razões (por exemplo, ao classificar coisas não numéricas, ou se você deseja que a classificação seja estável, o que não é possível usando simplesmente com um booleano)
Então, a pergunta é: por que os designers de Python decidiram deixar a sign
função fora da linguagem? Por que diabos se incomoda com copysign
e não com seus paissign
?
Estou esquecendo de algo?
EDIT - após o comentário de Peter Hansen. É justo o suficiente que você não o tenha usado, mas não disse para que usa o python. Em 7 anos que uso python, precisei inúmeras vezes, e o último é o canudo que quebrou as costas do camelo!
Sim, você pode passar o cmp por aí, mas 90% das vezes que eu precisava passá-lo estavam em um idioma como
lambda x,y: cmp(score(x),score(y))
aquele que funcionaria bem com o sinal.
Finalmente, espero que você concorde que isso sign
seria mais útil do que copysign
, mesmo que eu comprei sua opinião, por que se preocupar em definir isso em matemática, em vez de assinar? Como o copysign pode ser tão útil quanto assinar?
fonte
Respostas:
EDITAR:
Na verdade, havia um patch incluído
sign()
na matemática , mas não era aceito, porque eles não concordavam com o que deveria retornar em todos os casos extremos (+/- 0, +/- nan, etc)Por isso, eles decidiram implementar apenas o copysign, que (embora mais detalhado) pode ser usado para delegar ao usuário final o comportamento desejado para casos extremos - o que às vezes pode exigir a chamada
cmp(x,0)
.Não sei por que não é um built-in, mas tenho alguns pensamentos.
Mais importante,
copysign
é um superconjunto design
! Ligarcopysign
com x = 1 é o mesmo que umasign
função. Então você pode simplesmente usarcopysign
e esquecer .Se você ficar cansado de passar dois argumentos inteiros, poderá implementar
sign
dessa maneira, e ainda será compatível com o material IEEE mencionado por outros:Em segundo lugar, geralmente quando você quer o sinal de algo, acaba multiplicando-o por outro valor. E é claro que é basicamente o que
copysign
faz.Então, em vez de:
Você pode apenas fazer:
E sim, estou surpreso que você esteja usando o Python por 7 anos e pense que
cmp
poderia ser facilmente removido e substituído porsign
! Você nunca implementou uma classe com um__cmp__
método? Você nunca ligoucmp
e especificou uma função comparadora personalizada?Em resumo, também me vi querendo uma
sign
função, mascopysign
com o primeiro argumento sendo 1, funcionará bem. Discordo quesign
seria mais útil do quecopysign
, como mostrei que é apenas um subconjunto da mesma funcionalidade.fonte
[int(copysign(1, zero)) for zero in (0, 0.0, -0.0)]
dá[1, 1, -1]
. Isso deveria estar de[0, 0, 0]
acordo com en.wikipedia.org/wiki/Sign_functioncopysign(a,b)
retorna a com o sinal de b - b é a entrada variável, a é o valor para normalizar com o sinal de b. Nesse caso, o comentarista está ilustrando que o copysign (1, x) como substituto do sinal (x) falha, pois retorna 1 para x = 0, enquanto o sinal (0) seria avaliado como 0.cmp()
dará os resultados desejados, provavelmente para quase todos os casos com os quais alguém se preocuparia:[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ão é equivalente ab = copysign(b, a)
! Não considera o sinal de b. Por exemplo, sea=b=-1
o primeiro código retornar 1 enquanto o segundo retornar -1"copysign" é definido pela IEEE 754 e faz parte da especificação C99. É por isso que está em Python. A função não pode ser implementada integralmente pelo sinal abs (x) * (y), devido à forma como deve lidar com os valores de NaN.
Isso torna o copysign () uma função mais útil do que sign ().
Quanto a razões específicas pelas quais o signbit do IEEE (x) não está disponível no Python padrão, eu não sei. Eu posso fazer suposições, mas seria adivinhar.
O próprio módulo matemático usa o copysign (1, x) como uma maneira de verificar se x é negativo ou não negativo. Na maioria dos casos, lidar com funções matemáticas parece mais útil do que ter um sinal (x) que retorna 1, 0 ou -1 porque há um caso a menos a ser considerado. Por exemplo, o seguinte é do módulo de matemática do Python:
Lá você pode ver claramente que copysign () é uma função mais efetiva que uma função sign () de três valores.
Você escreveu:
Isso significa que você não sabe que cmp () é usado para outras coisas além de números. O cmp ("This", "That") não pode ser implementado com uma função sign ().
Editar para agrupar minhas respostas adicionais em outro lugar :
Você baseia suas justificativas em como abs () e sign () são frequentemente vistos juntos. Como a biblioteca padrão C não contém uma função 'sign (x)' de qualquer espécie, não sei como você justifica seus pontos de vista. Há um abs (int) e fabs (double) e fabsf (float) e fabsl (long), mas nenhuma menção de sinal. Há "copysign ()" e "signbit ()", mas eles se aplicam apenas aos números IEEE 754.
Com números complexos, o que o sinal (-3 + 4j) retornaria em Python, se fosse implementado? abs (-3 + 4j) retorna 5.0. Esse é um exemplo claro de como o abs () pode ser usado em lugares onde sign () não faz sentido.
Suponha que o sinal (x) foi adicionado ao Python, como um complemento ao abs (x). Se 'x' for uma instância de uma classe definida pelo usuário que implementa o método __abs __ (self), o abs (x) chamará x .__ abs __ (). Para funcionar corretamente, para lidar com abs (x) da mesma maneira, o Python precisará obter um slot de sinal (x).
Isso é excessivo para uma função relativamente desnecessária. Além disso, por que o sinal (x) existe e o não negativo (x) e o não positivo (x) não existem? Meu snippet da implementação do módulo matemático do Python mostra como o copybit (x, y) pode ser usado para implementar o nonnegative (), o que um simples sinal (x) não pode fazer.
O Python deve suportar um suporte melhor para a função matemática IEEE 754 / C99. Isso adicionaria uma função signbit (x), que faria o que você deseja no caso de carros alegóricos. Não funcionaria para números inteiros ou complexos, muito menos cadeias, e não teria o nome que você está procurando.
Você pergunta "por que" e a resposta é "o sinal (x) não é útil". Você afirma que é útil. No entanto, seus comentários mostram que você não sabe o suficiente para fazer essa afirmação, o que significa que você teria que mostrar evidências convincentes de sua necessidade. Dizer que o NumPy implementa isso não é suficientemente convincente. Você precisaria mostrar casos de como o código existente seria aprimorado com uma função de sinal.
E que está fora do escopo do StackOverflow. Leve-o para uma das listas de Python.
fonte
cmp()
nemsign()
:-)Outro forro para sinal ()
Se você deseja retornar 0 para x = 0:
fonte
cmp(x, 0)
é equivalentesign
elambda x: cmp(x, 0)
é mais legível do que você sugere.-1 if x < 0 else 1
?sign = lambda x: -1 if x < 0 else 1
é 15% mais rápido . O mesmo comsign = lambda x: x and (-1 if x < 0 else 1)
.Desde a
cmp
que foi removido , você pode obter a mesma funcionalidade comTrabalha para
float
,int
e mesmoFraction
. No caso defloat
, avisosign(float("nan"))
é zero.O Python não exige que as comparações retornem um valor booleano; portanto, coagir as comparações a bool () protege contra a implementação permitida, mas incomum:
fonte
Somente resposta correta compatível com a definição da Wikipedia
A definição na Wikipedia diz:
Conseqüentemente,
Que, para todos os efeitos, pode ser simplificado para:
Essa definição de função executa rapidamente e produz resultados corretos garantidos para 0, 0,0, -0,0, -4 e 5 (consulte os comentários para outras respostas incorretas).
Observe que zero (0) não é positivo nem negativo .
fonte
o numpy tem uma função de sinal e também oferece um bônus de outras funções. Assim:
Apenas tome cuidado para que o resultado seja um numpy.float64:
Para coisas como json, isso importa, pois o json não sabe como serializar tipos numpy.float64. Nesse caso, você pode fazer:
para obter uma flutuação regular.
fonte
Tente executar isso, onde x é qualquer número
A coerção para bool () lida com a possibilidade de o operador de comparação não retornar um booleano.
fonte
Sim, uma
sign()
função correta deve estar pelo menos no módulo de matemática - como é numpy. Porque freqüentemente é necessário para código orientado a matemática.Mas
math.copysign()
também é útil de forma independente.cmp()
eobj.__cmp__()
... geralmente têm alta importância independentemente. Não apenas para código orientado a matemática. Considere comparar / classificar tuplas, objetos de data, ...Os argumentos dev em http://bugs.python.org/issue1640 sobre a omissão de
math.sign()
são estranhos, porque:-NaN
sign(nan) == nan
sem preocupação (comoexp(nan)
)sign(-0.0) == sign(0.0) == 0
Sem se preocuparsign(-inf) == -1
Sem se preocupar- como está entorpecido
fonte
No Python 2,
cmp()
retorna um número inteiro: não é necessário que o resultado seja -1, 0 ou 1; portanto,sign(x)
não é o mesmo quecmp(x,0)
.No Python 3,
cmp()
foi removido em favor da comparação rica. Poiscmp()
, o Python 3 sugere o seguinte :o que é bom para cmp (), mas novamente não pode ser usado para sign () porque os operadores de comparação não precisam retornar booleanos .
Para lidar com essa possibilidade, os resultados da comparação devem ser coagidos aos booleanos:
Isso funciona para qualquer um
type
que seja totalmente ordenado (incluindo valores especiais comoNaN
ou infinitos).fonte
Você não precisa de um, basta usar:
fonte
x / abs(x)
demora um pouco mais do que apenas encadeamentoif/else
para verificar qual o lado de 0 a variável está ligada, ou para que o assunto usando o viscoso-ainda-satisfazendoreturn (x > 0) - (x < 0)
para subtrairbool
valores e retornar umint
True
eFalse
como1
e0
, você pode absolutamente fazer isso e obter qualquer1
,0
ou-1
.def sign(x): return (x > 0) - (x < 0)
não retornará umbool
, retornará umint
- se você passar,0
você0
retornará #Simplesmente não.
A melhor maneira de corrigir isso é:
fonte
A razão pela qual "sign" não está incluída é que, se incluíssemos todas as linhas úteis na lista de funções internas, o Python não seria mais fácil e prático de se trabalhar. Se você usa essa função com tanta frequência, por que não faz isso sozinha? Não é remotamente difícil ou mesmo tedioso fazê-lo.
fonte
abs()
fosse deixado de fora também.sign()
eabs()
são frequentemente usados juntos,sign()
é o mais útil dos dois (IMO), e nenhum é remotamente difícil ou tedioso de implementar (mesmo sendo propenso a erros, veja como esta resposta está errada: stackoverflow.com/questions/1986152/… )sign()
si só raramente é útil. O que você faz na maioria das vezes é seguir caminhos de código diferentes, com base no fato de uma variável ser positiva ou negativa e, nesse caso, é mais legível escrever a condição explicitamente.