왜 파이썬에는 부호 함수가 없습니까?


241

왜 파이썬에 sign함수 가 없는지 이해할 수 없습니다 . 그것은 abs(내 sign동생 이라고 생각) 내장되어 있지만 없습니다 sign.

파이썬 2.6에는 copysign함수 ( math )가 있지만 부호는 없습니다. 왜 copysign(x,y)당신이 그냥 쓸 sign수 있고 copysign직접에서 얻을 수있을 때 쓰는 것을 귀찮게 abs(x) * sign(y)합니까? 후자는 훨씬 더 명확합니다 : x는 y의 부호가있는 반면 copysign은 x가 y의 부호 또는 x의 부호가있는 경우 x를 기억해야합니다!

분명히 sign(x)더 많은 것을 제공하지는 않지만 이것보다 cmp(x,0)훨씬 더 읽기 쉽습니다 (파이썬과 같이 크게 읽을 수있는 언어의 경우 큰 장점이었습니다).

만약 내가 파이썬 디자이너라면, 다른 방법은 없을 것입니다 : cmp내장이 아니라 a sign. 필요할 때 (또는 숫자가 아닌 것들, x> y 만 더 잘 cmp(x,y)할 수 있습니다 sign(x-y)-물론 sorted정수 비교기 대신 부울을 수락 해야합니다 ). 긍정적 인 경우 x>y( 첫 번째cmp 때 긍정적 인 협약을 기억해야 하지만 반대 방향 일 수 있음) 더 명확 합니다. 물론 다른 이유로 (예를 들어 숫자가 아닌 것을 정렬 할 때 또는 정렬을 안정적으로 만들고 싶을 때 부울과 함께 사용할 수없는 경우) 자체적으로 의미가 있습니다.cmp

그렇다면 문제는 왜 파이썬 디자이너가 sign함수를 언어 에서 벗어나기로 결정 했는가하는 것입니다. 도대체 왜 copysign부모가 sign아닌가?

뭔가 빠졌습니까?

편집-Peter Hansen 의견 후. 당신이 그것을 사용하지 않을 정도로 공평하지만 파이썬을 무엇에 사용하는지 말하지 않았습니다. 내가 파이썬을 사용하는 7 년 동안, 나는 그것을 여러 번 필요로했고 마지막은 낙타의 등을 부러 뜨린 빨대입니다!

그렇습니다. cmp를 전달할 수는 있지만 통과 해야하는 시간의 90 %는 관용구와 lambda x,y: cmp(score(x),score(y))잘 맞았 을 것입니다.

마지막으로, 나는 당신 sign보다 더 유용 할 것이라는 데 동의하기를 바랍니다 copysign. 그래서 당신의 견해를 사더라도 사인 대신 수학으로 정의하는 것을 왜 귀찮게합니까? copysign이 sign보다 어떻게 그렇게 유용 할 수 있습니까?


33
@ dmazzoni :이 주장 이이 사이트의 모든 질문에 작동하지 않습니까? 스택 오버 플로우를 닫고 모든 질문을 관련 주제 개발자 또는 사용자 메일 링리스트에 요청하십시오!
Davide

43
질문에 대한 적절한 장소는 답변을받을 수있는 곳입니다. 따라서 stackoverflow는 적절한 장소입니다.
Stefano Borini

23
-1 : @Davide : "Why"및 "What not"질문은 일반적으로 여기에 대답 할 수 없습니다. 파이썬 개발의 대부분의 주체는 여기서 질문에 대답하지 않기 때문에 "왜"또는 "왜"질문에 대한 답변을 거의 얻지 못합니다. 또한 해결할 문제가 없습니다. 당신은 폭죽이있는 것처럼 들립니다. 문제가있는 경우 ( "이 예제에서 부호 부족 문제를 해결하려면 ...") 합리적입니다. 이 장소에서는 "왜 안 돼?"
S.Lott

31
질문은 약간 감정적 일 수 있지만, 이것이 나쁜 질문이라고 생각하지 않습니다. 많은 사람들이 빌트인 부호 기능을 찾았 기 때문에 이것이없는 이유가 궁금 할 것입니다.
FogleBird

17
이것은 왜 객관적인 질문인가?“왜”파이썬에 주어진 기능이 부족한 이유는 파이썬 디자인 개발자 또는 python-dev 또는 다른 포럼 (때때로 블로그 게시물)의 적절한 토론에 링크하여 답변 할 수있는 언어 디자인의 역사에 대한 합법적 인 질문입니다. 핵심 개발자는 주제를 해시합니다. 이전에 python-dev에서 약간의 역사를 찾기 위해 Google에 시도한 결과, 언어를 처음 접하는 사람들이 왜 막 다른 골목에 부딪 히고 더 경험이 많은 Python 사람이 대답하기를 희망하는지 여기에 요청할 수 있습니다!
Brandon Rhodes

답변:


228

편집하다:

실제로 math에 포함 된 패치 가 있었지만 모든 엣지 케이스 (+/- 0, +/- nan 등) 에서 반환해야하는 것에 동의하지 않았기 때문에 승인되지 않았습니다.sign()

그들이 구현하기로 결정 그래서에만 할 수있는 (더 자세한하지만), copysign 최종 사용자 가장자리 경우에 원하는 동작에 위임하는 데 사용 - 때로는 호출이 필요할 수 있습니다cmp(x,0) .


왜 내장되어 있지 않은지 모르겠지만 몇 가지 생각이 있습니다.

copysign(x,y):
Return x with the sign of y.

가장 중요한 copysign것은의 슈퍼 세트입니다 sign! copysignx = 1로 호출 하는 것은 sign함수 와 같습니다 . 그래서 당신은 그것을 사용 copysign하고 잊을 수 있습니다.

>>> math.copysign(1, -4)
-1.0
>>> math.copysign(1, 3)
1.0

두 개의 전체 인수를 전달하는 데 어려움을 겪으면 sign이 방법을 구현할 수 있으며 다른 사람들이 언급 한 IEEE와 호환됩니다.

>>> sign = functools.partial(math.copysign, 1) # either of these
>>> sign = lambda x: math.copysign(1, x) # two will work
>>> sign(-4)
-1.0
>>> sign(3)
1.0
>>> sign(0)
1.0
>>> sign(-0.0)
-1.0
>>> sign(float('nan'))
-1.0

둘째, 일반적으로 무언가의 징조를 원할 때 다른 값을 곱하면됩니다. 물론 그것은 기본적으로 무엇을 하는가 copysign입니다.

따라서 대신 :

s = sign(a)
b = b * s

당신은 할 수 있습니다 :

b = copysign(b, a)

그리고 네, 당신이 7 년 동안 파이썬을 사용하고 있다는 사실에 놀랐고 cmp그렇게 쉽게 제거하고 대체 할 수 있다고 생각 합니다 sign! __cmp__메소드를 사용 하여 클래스를 구현 한 적이 있습니까? cmp커스텀 비교기 함수를 호출 하고 지정한 적이 있습니까?

요약하면, 나는 나 자신 sign도 함수를 원한다는 것을 알았지 만 copysign첫 번째 인수가 1이면 잘 작동합니다. 나는 그것이 동일한 기능의 하위 집합이라는 것을 보여 주었기 sign때문에보다 유용하다고 동의하지 copysign않습니다.


35
사용이 [int(copysign(1, zero)) for zero in (0, 0.0, -0.0)]있습니다 [1, 1, -1]. 즉 있었어야 [0, 0, 0]에 따라 en.wikipedia.org/wiki/Sign_function
user238424

12
@Andrew-@ user238424의 전화 순서가 정확합니다. copysign(a,b)b의 부호를 가진 a를 반환합니다.-b는 변화하는 입력이고, a는 b의 부호로 정규화 할 값입니다. 이 경우 주석자는 x (0)에 대해 1을 반환하고 sign (0)은 0으로 평가되므로 sign (x)의 대체물 인 copysign (1, x)가 실패한다고 설명합니다.
PaulMcG

7
플로트는 "부호"를 "값"과 분리합니다. -0.0은 구현 오류로 보일지라도 음수입니다. 간단히 사용 cmp()하면 거의 모든 경우에 대해 원하는 결과를 얻을 수 있습니다. [cmp(zero, 0) for zero in (0, 0.0, -0.0, -4, 5)]==> [0, 0, 0, -1, 1].
pythonlarry

11
s = sign(a) b = b * s와 동일하지 않습니다 b = copysign(b, a)! b의 부호는 고려하지 않습니다. 예를 a=b=-1들어 첫 번째 코드는 1을 반환하고 두 번째 코드는 -1을 반환하면
Johannes Jendersie

14
잘못된 sign () 대체 정의, sign (a)를 사용한 곱셈에 대한 거짓 등가, copysign의 동기 부여에 대한 잘못된 설명 및 질문에 이미 언급 된 올바른 대체 "cmp (x, 0)"을 참조하십시오. 정보가 많지 않고 왜 이것이 많은 투표를 통해 "허용되는"답변인지 명확하지 않습니다.?
kxr

59

"copysign"은 IEEE 754 및 C99 사양의 일부로 정의됩니다. 그것이 파이썬에있는 이유입니다. NaN 값을 처리하는 방식 때문에 abs (x) * sign (y)로 함수를 완전히 구현할 수 없습니다.

>>> import math
>>> math.copysign(1, float("nan"))
1.0
>>> math.copysign(1, float("-nan"))
-1.0
>>> math.copysign(float("nan"), 1)
nan
>>> math.copysign(float("nan"), -1)
nan
>>> float("nan") * -1
nan
>>> float("nan") * 1
nan
>>> 

따라서 copysign ()이 sign ()보다 유용한 함수가됩니다.

IEEE의 signbit (x)를 표준 파이썬에서 사용할 수없는 특정 이유에 대해서는 모르겠습니다. 나는 가정을 할 수 있지만 추측 할 것입니다.

수학 모듈 자체는 x가 음수인지 음수가 아닌지 확인하는 방법으로 copysign (1, x)을 사용합니다. 고려해야 할 경우가 적기 때문에 1, 0 또는 -1을 반환하는 sign (x)보다 더 유용한 수학 함수를 다루는 대부분의 경우. 예를 들어 다음은 Python의 수학 모듈에서 가져온 것입니다.

static double
m_atan2(double y, double x)
{
        if (Py_IS_NAN(x) || Py_IS_NAN(y))
                return Py_NAN;
        if (Py_IS_INFINITY(y)) {
                if (Py_IS_INFINITY(x)) {
                        if (copysign(1., x) == 1.)
                                /* atan2(+-inf, +inf) == +-pi/4 */
                                return copysign(0.25*Py_MATH_PI, y);
                        else
                                /* atan2(+-inf, -inf) == +-pi*3/4 */
                                return copysign(0.75*Py_MATH_PI, y);
                }
                /* atan2(+-inf, x) == +-pi/2 for finite x */
                return copysign(0.5*Py_MATH_PI, y);

여기서 copysign ()이 3 값 sign () 함수보다 더 효과적인 함수임을 분명히 알 수 있습니다.

당신은 썼습니다 :

파이썬 디자이너라면 cmp ()는 내장되어 있지 않지만 sign ()

이것은 cmp ()가 숫자 이외의 것에 사용된다는 것을 모른다는 것을 의미합니다. cmp ( "This", "That")은 sign () 함수로 구현할 수 없습니다.

다른 곳에서 추가 답변을 수집하도록 편집하십시오 .

abs ()와 sign ()이 종종 어떻게 보이는지에 대한 근거를 제시합니다. C 표준 라이브러리에는 어떤 종류의 'sign (x)'함수가 포함되어 있지 않으므로보기를 정당화하는 방법을 모르겠습니다. abs (int) 및 fabs (double) 및 fabsf (float) 및 fabsl (long)이 있지만 부호에 대한 언급은 없습니다. "copysign ()"및 "signbit ()"이 있지만 IEEE 754 숫자에만 적용됩니다.

복잡한 숫자를 사용하면 파이썬에서 sign (-3 + 4j) 반환되는 것은 무엇입니까? abs (-3 + 4j)는 5.0을 반환합니다. sign ()이 의미가없는 곳에서 abs ()를 사용하는 방법에 대한 명확한 예입니다.

abs (x)의 보완으로 sign (x)가 Python에 추가되었다고 가정합니다. 'x'가 __abs __ (self) 메소드를 구현하는 사용자 정의 클래스의 인스턴스 인 경우 abs (x)는 x .__ abs __ ()를 호출합니다. 올바르게 작동하려면 동일한 방식으로 abs (x)를 처리하려면 파이썬이 부호 (x) 슬롯을 가져와야합니다.

상대적으로 필요하지 않은 기능에는 과도합니다. 게다가 sign (x)가 존재하고 nonnegative (x)와 nonpositive (x)가 존재하지 않는 이유는 무엇입니까? 파이썬의 수학 모듈 구현에서 내 스 니펫은 copybit (x, y)를 사용하여 간단한 부호 (x)가 할 수없는 음이 아닌 ()을 구현하는 방법을 보여줍니다.

파이썬은 IEEE 754 / C99 수학 함수를 더 잘 지원해야합니다. 부동 소수점의 경우 원하는 것을 수행하는 signbit (x) 함수가 추가됩니다. 정수 또는 복소수, 훨씬 적은 문자열에서는 작동하지 않으며 찾고있는 이름이 없습니다.

"왜"를 물어 보면 "sign (x)는 쓸모가 없습니다." 당신은 그것이 유용하다고 주장합니다. 그러나 당신의 의견은 당신이 그 주장을 할 수있을만큼 충분히 알지 못한다는 것을 보여줍니다. NumPy가 구현한다고 말하면 충분하지 않습니다. 부호 함수를 사용하여 기존 코드를 개선하는 방법을 보여 주어야합니다.

그리고 그것은 StackOverflow의 범위를 벗어났습니다. 대신 파이썬 목록 중 하나로 가져 가십시오.


5
글쎄, 그것이 당신을 행복하게 만들지는 않겠지 만, 파이썬 3도 다음 cmp()과 같은 것도 없습니다 sign():-)
Antoine P.

4
IEEE 754에서 제대로 작동하는 좋은 sign () 함수를 작성하는 것은 쉽지 않습니다. 질문에이 요점을 자세히 설명하지 않더라도 언어를 제외시키는 것이 아니라 언어에 포함시키는 것이 좋습니다.
Davide

2
"정렬을 안정적으로 유지하려는 경우"에 대한 의견은 정렬이 어떻게 안정적인지 알지 못한다는 의미입니다. copysign과 sign이 동등하다는 내용은이 게시물 이전의 IEEE 754 수학에 대해 잘 몰랐 음을 나타냅니다. 파이썬은 모든 754 수학 함수를 핵심으로 구현해야합니까? C99가 아닌 컴파일러의 경우 어떻게해야합니까? 754가 아닌 플랫폼? "비 음성"및 "비 양성"도 유용한 기능이다. 파이썬도 그것들을 포함해야합니까? abs (x)는 x .__ abs __ ()를 참조하므로 sign (x)는 x .__ sign __ ()을 참조해야합니까? 수요가 적거나 필요하지 않은 이유는 무엇입니까?
Andrew Dalke

2
math.copysign (1, float ( "-nan"))은 2.7에서 시도하면 -1.0 대신 1.0을 반환합니다.
dansalmo

34

sign ()을위한 또 하나의 라이너

sign = lambda x: (1, -1)[x<0]

x = 0에 대해 0을 반환하려면 다음을 수행하십시오.

sign = lambda x: x and (1, -1)[x<0]

1
왜? 질문 자체가 그 인정 cmp(x, 0)에 해당 sign하고, lambda x: cmp(x, 0)당신이 제안하는 것보다 더 많은 읽을 수 있습니다.
ToolmakerSteve

1
사실, 나는 틀렸다. 'cmp'가 -1,0, + 1을 반환하도록 지정되었다고 가정했지만 사양이이를 보장하지는 않습니다.
ToolmakerSteve

아름다운. 시작된 질문에 대답하십시오 : python int 또는 float to -1, 0, 1?
scharfmn

1
대신 목록을 사용하면 어떤 이점이 -1 if x < 0 else 1있습니까?
Mateen Ulhaq

6
sign = lambda x: -1 if x < 0 else 1이다 15 % 더 빠르게 . 와 동일합니다 sign = lambda x: x and (-1 if x < 0 else 1).
Mateen Ulhaq

26

이후 cmp되었습니다 제거 , 당신과 같은 기능을 얻을 수 있습니다

def cmp(a, b):
    return (a > b) - (a < b)

def sign(a):
    return (a > 0) - (a < 0)

그것은 작동 float, int심지어 Fraction. 의 경우 float통지 sign(float("nan"))는 0입니다.

파이썬은 비교가 부울을 반환하도록 요구하지 않으므로 bool ()에 비교를 강제하면 허용되지만 드물게 구현되는 것을 방지합니다.

def sign(a):
    return bool(a > 0) - bool(a < 0)

13

Wikipedia 정의를 준수하는 정답 만

Wikipedia에 대한 정의는 다음과 같습니다.

부호 정의

그 후,

sign = lambda x: -1 if x < 0 else (1 if x > 0 else (0 if x == 0 else NaN))

모든 의도와 목적을 위해 다음과 같이 단순화 할 수 있습니다.

sign = lambda x: -1 if x < 0 else (1 if x > 0 else 0)

이 기능 정의 빨리 실행하는 수율은 보장 , 0 올바른 결과를 0.0, -0.0, -4, 5 (다른 잘못된 답변에 의견을 참조).

참고 제로 (0)가도 긍정적이나 부정적인이다 .


1
이 답변은 간결하면서도 강력한 파이썬이 될 수있는 방법을 보여줍니다.
NelsonGon 2016 년

1
Quibble : 코드는 WP 정의를 구현하지 않으며 중간 절을 마지막에 기본 절로 바꿉니다. 이것은 nan과 같이 실수가 아닌 숫자를 처리하는 데 필요하지만 WP 문을 직접 따르는 것으로 잘못 표시됩니다 ( '따라서').
Jürgen Strobel

1
@ JürgenStrobel 나는 당신이 의미하는 바를 정확히 알고 있으며 오랫동안이 문제를 고민해 왔습니다. 나는 대부분의 유스 케이스에 대한 단순화 된 버전을 유지하면서 올바른 형식에 대한 답변을 확장했습니다.
Stroobandt Serge

10

numpy에는 부호 기능이 있으며 다른 기능도 제공합니다. 그래서:

import numpy as np
x = np.sign(y)

결과가 numpy.float64인지주의하십시오.

>>> type(np.sign(1.0))
<type 'numpy.float64'>

json은 numpy.float64 유형을 직렬화하는 방법을 모르기 때문에 json과 같은 것이 중요합니다. 이 경우 다음을 수행 할 수 있습니다.

float(np.sign(y))

정기적 인 플로트를 얻습니다.


10

여기서 x는 숫자입니다.

int_sign = bool(x > 0) - bool(x < 0)

bool ()에 대한 강제 는 비교 연산자가 부울을 리턴하지 않을 가능성 을 처리합니다 .


좋은 생각이지만, 나는 당신이 의미한다고 생각합니다 : int_sign = int (x> 0)-int (x <0)
yucer

int_sign = 람다 x : (x> 0)-(x <0)
yucer

1
@yucer no, 그는 실제로 설명에 대한 링크를 제공 할 수있는 이론적 가능성 때문에 bool 캐스트 (int의 하위 클래스)를 의미했습니다.
Walter Tross

이 구조의 유일한 단점은 인수가 두 번 나타납니다. 이는 단일 변수 인 경우에만
좋습니다

5

예, sign()적어도 수학 모듈 에는 올바른 기능이 있어야합니다. 수학 지향 코드에는 자주 필요하기 때문입니다.

그러나 math.copysign()독립적으로도 유용합니다.

cmp()그리고 obj.__cmp__()... 일반적으로 독립적으로 중요성이 높습니다. 수학 중심 코드 만이 아닙니다. 튜플, 날짜 객체 등을 비교 / 정렬하는 것을 고려하십시오 ...

http://bugs.python.org/issue1640 의 dev 인수는 다음 과 같은 math.sign()이유로 이상합니다.

  • 별도는 없습니다 -NaN
  • sign(nan) == nan 걱정없이 (같은 exp(nan))
  • sign(-0.0) == sign(0.0) == 0 걱정없이
  • sign(-inf) == -1 걱정없이

-숫자 그대로


4

Python 2에서는 cmp()정수를 반환합니다. 결과는 -1, 0 또는 1 일 필요 sign(x)가 없으므로와 같지 않습니다 cmp(x,0).

파이썬 3에서는 cmp()풍부한 비교를 위해 제거되었습니다. 들어 cmp()파이썬 3가, 이 제안 :

def cmp(a, b):
    return (a > b) - (a < b)

이것은 cmp ()에는 좋지만 비교 연산자는 부울을 반환 할 필요가 없으므로 sign ()에 다시 사용할 수 없습니다 .

이 가능성을 처리하려면 비교 결과를 부울로 강제 변환해야합니다.

 def sign(a):
    return bool(x > 0) - bool(x < 0)

이것은 type완전히 주문 된 모든 것 (예 : 특수 값 NaN이나 무한대 포함)에 적용됩니다.


0

당신은 하나를 필요로하지 않습니다, 당신은 단지 사용할 수 있습니다 :

If not number == 0:
    sig = number/abs(number)
else:
    sig = 0

4
그것은 그 지적 곰 x / abs(x)단 체인보다 약간 길게 걸리는 if/else변수에, 또는하여 그 문제 칙칙한을 아직 만족하는 0의 어느 쪽 확인 return (x > 0) - (x < 0)bool값과 리턴int

1
파이썬 취급 TrueFalse같이 1하고 0, 당신은 절대적으로이 작업을 수행하고 중 하나를 얻을 수 있습니다 1, 0또는 -1. def sign(x): return (x > 0) - (x < 0)를 반환하지 않습니다 bool, 그것은을 반환 할 것이다 int- 당신이 통과하면 0당신이 얻을 것이다 0다시

0

그렇지 않습니다.

이를 해결하는 가장 좋은 방법은 다음과 같습니다.

sign = lambda x: bool(x > 0) - bool(x < 0)

-8

"sign"이 포함되지 않은 이유는 내장 함수 목록에 모든 유용한 one-liner를 포함하면 더 이상 작업하기가 Python이 쉽고 실용적이지 않기 때문입니다. 이 기능을 너무 자주 사용한다면, 왜 스스로이 기능을 제거하지 않습니까? 원격으로 힘들거나 지루한 것 같지는 않습니다.


6
글쎄, 나도 이것을 제외하고 이것을 사겠다 abs(). sign()abs()종종 함께 사용, sign()두 (IMO)의 가장 유용하고, 아무도, 심지어의 오류가 발생하기 쉬운 불구하고 (구현이 대답이 오해 방식을 볼 수 원격으로 어렵거나 지루하지 : stackoverflow.com/questions/1986152/... )
Davide

1
문제는 그 sign()자체 의 수치 결과 가 거의 유용하지 않다는 것입니다 . 대부분의 시간은 변수가 양수인지 음수인지에 따라 다른 코드 경로를 사용하므로 조건을 명시 적으로 작성하는 것이 더 읽기 쉽습니다.
Antoine P.

3
abs ()는 sign ()보다 훨씬 자주 사용됩니다. 그리고 당신이 NumPy 추적기를 가리키며 sign ()이 얼마나 어려운지를 보여줍니다. 부호 (-3 + 4j)는 무엇이되어야합니까? abs (-3 + 4j)는 5.0이지만 sign ()과 abs ()가 종종 함께 나타나는 주장을합니다. C 표준 라이브러리에는 '기호'기능이 없으므로 데이터를 어디서 구할 수 있습니까?
Andrew Dalke
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.