Почему у Python нет знаковой функции?

Я не могу понять, почему у Python нет функции sign. Он имеет встроенный abs (который я считаю сестрой sign), но не sign.

В python 2.6 существует даже функция copysignmath), но нет знака. Зачем писать copysign(x,y), когда вы могли бы просто написать sign, а затем получить copysign непосредственно из abs(x) * sign(y)? Последнее было бы намного яснее: x со знаком y, тогда как с copysign вы должны помнить, если он x со знаком y или y со знаком x!

Очевидно, что sign(x) не предоставляет ничего больше, чем cmp(x,0), но было бы гораздо более читаемым, что это тоже (и для сильно читаемого языка, такого как python, это было бы большим плюсом).

Если бы я был дизайнером python, я был бы другим способом: no cmp builtin, но sign. Когда вам нужно cmp(x,y), вы можете просто сделать sign(x-y) (или, что еще лучше, для не численного материала, просто x > y), конечно, это должно было потребовать sorted принятия логического значения вместо целочисленного компаратора). Это также было бы более ясным: положительный, когда x>y (тогда как cmp вы должны помнить соглашение положительное, когда first больше, но это может быть наоборот). Конечно, cmp имеет смысл по своему усмотрению по другим причинам (например, при сортировке нечисловых вещей или если вы хотите, чтобы сортировка была стабильной, что невозможно использовать с помощью простого логического выражения)

Итак, возникает вопрос: почему разработчики Python решили оставить функцию sign вне языка? Почему черт не беспокоиться с copysign, а не его родителем sign?

Я что-то пропустил?

EDIT - после комментария Питера Хансена. Достаточно справедливо, что вы его не использовали, но вы не сказали, для чего вы используете python. Через 7 лет, когда я использую python, мне нужно было много раз, а последняя - соломинкой, которая сломала верблюда!

Да, вы можете передать cmp, но 90% времени, которое мне нужно было передать, было в идиоме вроде lambda x,y: cmp(score(x),score(y)), который отлично работал бы со знаком.

Наконец, я надеюсь, вы согласитесь, что sign был бы более полезен, чем copysign, поэтому, даже если бы я купил ваше мнение, зачем беспокоиться об определении этого в математике вместо того, чтобы подписывать? Как copysign может быть так полезен, как знак?

+211
источник поделиться
11 ответов

EDIT:

Действительно, был патч, который включал sign() в math, но это не было принято, потому что они не согласились на то, что он должен вернуть во всех случаях кросс (+/-0, +/- nan и т.д.)

Поэтому они решили реализовать только copysign, который (хотя и более подробный) может быть используемый для делегирования конечному пользователю желаемого поведения для краевых случаев - который иногда может потребовать вызова cmp(x,0).


Я не знаю, почему это не встроенный, но у меня есть некоторые мысли.

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

Самое главное, copysign является надмножеством sign! Вызов copysign с x = 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)

И да, я удивлен, что вы использовали Python в течение 7 лет и считаете, что cmp можно легко удалить и заменить на sign! Вы никогда не реализовывали класс с помощью метода __cmp__? Вы никогда не вызывали cmp и не задавали функцию пользовательского сравнения?

В общем, я тоже нашел функцию sign, но copysign с первым аргументом равным 1 будет работать нормально. Я не согласен с тем, что sign был бы более полезен, чем copysign, поскольку я показал, что это всего лишь подмножество одной и той же функциональности.

+201
источник

"copysign" определяется IEEE 754 и частью спецификации C99. Вот почему это в Python. Функция не может быть полностью реализована символом abs (x) * (y) из-за того, как она должна обрабатывать значения NaN.

>>> 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) недоступен в стандартном Python, я не знаю. Я могу делать предположения, но это было бы угадать.

Сам математический модуль использует signbit (1, x) как способ проверить, является ли x отрицательным или неотрицательным. В большинстве случаев речь идет о математических функциях, которые кажутся более полезными, чем наличие знака (x), который возвращает 1, 0 или -1, потому что есть еще один случай для рассмотрения. Например, следующее из математического модуля 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() является более эффективной функцией, чем трехзначная функция sign().

Вы писали:

Если бы я был разработчиком python, я был бы другим способом: no cmp() builtin, но знак()

Это означает, что вы не знаете, что cmp() используется для вещей помимо чисел. cmp ("This", "That" ) не может быть реализовано с помощью функции sign().

Изменить, чтобы сортировать мои дополнительные ответы в другом месте:

Вы основываете свои обоснования на том, как abs() и sign() часто видны вместе. Поскольку стандартная библиотека C не содержит функции "sign (x)" любого типа, я не знаю, как вы оправдываете свои взгляды. Там есть абс (int) и fabs (double) и fabsf (float) и fabsl (long), но не упоминается знак. Существует "copysign()" и "signbit()", но они применимы только к номерам IEEE 754.

С комплексными числами, что бы подписать (-3 + 4j) возврат в Python, было ли это реализовано? abs (-3 + 4j) return 5.0. Это ясный пример того, как abs() можно использовать в местах, где знак() не имеет смысла.

Предположим, что знак (x) был добавлен в Python как дополнение к abs (x). Если "x" - это экземпляр пользовательского класса, который реализует метод __abs __ (self), тогда abs (x) вызовет x.__ abs __(). Чтобы правильно работать, для обработки абс (x) таким же образом, Python должен будет получить слот (x).

Это чрезмерно для относительно ненужной функции. Кроме того, почему знак (x) существует и неотрицательный (x) и неположительный (x) не существует? Мой фрагмент из реализации математического модуля Python показывает, как copybit (x, y) можно использовать для реализации неотрицательных(), которые простой знак (x) не может сделать.

Python должен поддерживать лучшую поддержку математической функции IEEE 754/C99. Это добавит функцию signbit (x), которая будет делать то, что вы хотите, в случае float. Он не будет работать для целых чисел или сложных чисел, а тем более строк, и у него не будет имени, которое вы ищете.

Вы спрашиваете "почему", а ответ "знак (x) не полезен". Вы утверждаете, что это полезно. Однако ваши комментарии показывают, что вы не знаете достаточно, чтобы иметь возможность сделать это утверждение, а это означает, что вам нужно будет показать убедительные доказательства его необходимости. Говоря, что NumPy реализует, это недостаточно убедительно. Вам нужно будет показать примеры того, как существующий код будет улучшен с помощью знаковой функции.

И это выходит за рамки StackOverflow. Возьмите его вместо одного из списков Python.

+55
источник

Еще один лайнер для знака()

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

Если вы хотите, чтобы он возвращал 0 для x = 0:

sign = lambda x: x and (1, -1)[x<0]
+30
источник

Поскольку 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")) равно нулю.

Python не требует, чтобы сравнения возвращали логическое значение, поэтому принудительное сравнение сравнений с bool() защищает от допустимой, но необычной реализации:

def sign(a):
    return bool(a > 0) - bool(a < 0)
+19
источник

Попробуйте запустить это, где x - любое число

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

Принуждение к bool() обрабатывает возможность, чтобы оператор сравнения не возвращал логическое значение.

+7
источник

Только правильный ответ, соответствующий определению Википедии

определение в Википедии гласит:

sign definition

Следовательно,

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

Это определение функции выполняет быстро и дает гарантированные правильные результаты для 0, 0.0, -0.0, -4 и 5 (см. комментарии к другим неверным). ответы).

Обратите внимание, что ноль (0) не является ни положительным, ни отрицательным.

+7
источник

numpy имеет функцию знака и дает вам бонус других функций. Итак:

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

Просто будьте осторожны, чтобы результат был numpy.float64:

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

Для таких вещей, как json, это имеет значение, поскольку json не знает, как сериализовать типы numpy.float64. В этом случае вы можете сделать:

float(np.sign(y))

чтобы получить регулярный поплавок.

+6
источник

Да, правильная функция sign() должна быть, по крайней мере, в математическом модуле, так как она находится в numpy. Потому что это часто требуется для математического ориентированного кода.

Но math.copysign() также полезен независимо.

cmp() и obj.__cmp__()... имеют в целом большое значение независимо. Не только для математического ориентированного кода. Рассмотрим сравнение/сортировку кортежей, объектов даты,...

Аргументы dev http://bugs.python.org/issue1640 относительно пропуска math.sign() нечетны, потому что:

  • Нет отдельного -NaN
  • sign(nan) == nan без проблем (например, exp(nan))
  • sign(-0.0) == sign(0.0) == 0 без проблем
  • sign(-inf) == -1 без проблем

- как в numpy

+4
источник

В Python 2 cmp() возвращает целое число: не требуется, чтобы результат был -1, 0 или 1, поэтому sign(x) не совпадает с cmp(x,0).

В Python 3 cmp() была удалена в пользу расширенного сравнения. Для cmp() Python 3 предлагает следующее:

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

что хорошо для cmp(), но опять же не может использоваться для sign(), потому что операторам сравнения не нужно возвращать логические значения.

Чтобы справиться с этой возможностью, результаты сравнения должны быть приведены к логическим значениям:

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

Это работает для любого type который полностью упорядочен (включая специальные значения, такие как NaN или бесконечности).

+1
источник

Вам не нужен он, вы можете просто использовать:

If not number == 0:
    sig = number/abs(number)
else:
    sig = 0
0
источник

Причина "знака" не включена в то, что если бы мы включили каждый полезный однострочный в список встроенных функций, Python было бы нелегко и практично работать с ним больше. Если вы часто используете эту функцию, почему бы вам не рассказать об этом сами? Это не так, как будто это трудно или даже утомительно.

-6
источник

Посмотрите другие вопросы по меткам или Задайте вопрос