отрицательный ноль в питоне

Я обнаружил отрицательный ноль в выводе Python; он создается, например, следующим образом:

k = 0.0
print(-k)

На выходе будет -0.0.

Однако, когда я сравниваю -k с 0,0 на равенство, получается True. Есть ли разница между 0.0 и -0.0 (меня не волнует, что они предположительно имеют разное внутреннее представление; меня волнует только их поведение в программе). Есть ли какие-то скрытые ловушки, о которых я должен знать?


person max    schedule 03.11.2010    source источник
comment
Он не дает отрицательного значения с python 2.5.4   -  person Ankit Jaiswal    schedule 03.11.2010
comment
Настоящая скрытая ловушка - это когда вы начинаете тестирование на равенство со значениями с плавающей запятой. Они неточны и склонны к странным неточностям при округлении.   -  person Sean McSomething    schedule 04.11.2010
comment
Но он выводит отрицательное значение на Python 2.7.1.   -  person syntagma    schedule 05.03.2013
comment
Эта проблема возникла в реальном приложении GPS; долгота чуть западнее меридиана сообщалась как ноль градусов и х минут, тогда как она должна была быть минус ноль градусов и х минут. Но python не может представлять целочисленный отрицательный ноль.   -  person secret squirrel    schedule 01.09.2016


Ответы (5)


Посмотрите −0 (число) в Википедии

В основном IEEE действительно определяет отрицательный ноль.

И по этому определению для всех целей:

-0.0 == +0.0 == 0

Я согласен с aaronasterling, что -0.0 и +0.0 являются разными объектами. Уравнивание их (оператор равенства) гарантирует, что в код не будут внесены тонкие ошибки.
Подумайте о a * b == c * d

>>> a = 3.4
>>> b =4.4
>>> c = -0.0
>>> d = +0.0
>>> a*c
-0.0
>>> b*d
0.0
>>> a*c == b*d
True
>>> 

[Изменить: дополнительная информация на основе комментариев]

Когда я сказал это для всех практических целей, я выбрал это слово довольно поспешно. Я имел в виду стандартное сравнение на равенство.

Как сказано в ссылке, стандарт IEEE определяет сравнение так, чтобы +0 = -0, а не -0 < +0. Хотя можно всегда игнорировать знак нуля, стандарт IEEE этого не делает. Когда при умножении или делении используется знаковый ноль, при вычислении знака ответа применяются обычные правила знаков.

Такие операции, как divmod и atan2, демонстрируют это поведение. Фактически atan2 соответствует определению IEEE, как и базовая библиотека C.

>>> divmod(-0.0,100)
(-0.0, 0.0)
>>> divmod(+0.0,100)
(0.0, 0.0)

>>> math.atan2(0.0, 0.0) == math.atan2(-0.0, 0.0)
True 
>>> math.atan2(0.0, -0.0) == math.atan2(-0.0, -0.0)
False

Один из способов - выяснить в документации, соответствует ли реализация требованиям IEEE. Из обсуждения также кажется, что существуют и тонкие вариации платформ.

Однако этот аспект (соответствие определению IEEE) соблюдался не везде. См. Отказ от PEP 754 из-за отсутствия интереса! Я не уверен, что это было позже.

См. Также Что должен знать каждый компьютерный ученый об арифметике с плавающей запятой .

person pyfunc    schedule 03.11.2010
comment
@aaronasterling: Почему вы удалили свой ответ? Это было ценным дополнением к информации здесь. Я только что проголосовал за это. - person pyfunc; 03.11.2010
comment
потому что я ошибался насчет последней части, а остальное не было уникальным для моего поста. - person aaronasterling; 03.11.2010
comment
Если он одинаков для всех целей, как это объясняет разницу в atan2 в ответе Крейга МакКуина? Я согласен с тем, что он возвращает True при сравнении на равенство, но если поведение двух чисел может отличаться, я хотел бы знать, когда. - person max; 03.11.2010
comment
@max Обратите внимание, что функция арктангенса в основном ищет наклон (и направление) предоставленных аргументов, поэтому внутренне деление на ноль приводит к разрывам, что не должно вызывать удивления. Кроме того, выход функции является циклическим с периодом 2π, + π и -π одинаковы. - person Nick T; 11.03.2014

Это имеет значение для функции atan2() (по крайней мере, в некоторые реализации). В моем Python 3.1 и 3.2 в Windows (который основан на базовой реализации C, согласно примечанию Детали реализации CPython рядом с нижняя часть документации модуля Python math):

>>> import math
>>> math.atan2(0.0, 0.0)
0.0
>>> math.atan2(-0.0, 0.0)
-0.0
>>> math.atan2(0.0, -0.0)
3.141592653589793
>>> math.atan2(-0.0, -0.0)
-3.141592653589793
person Craig McQueen    schedule 03.11.2010

math.copysign() обрабатывает -0.0 и +0.0 по-разному, если вы не используете Python на странная платформа:

math. copysign (x, y)
Возвращает x со знаком y . На платформе, которая поддерживает нули со знаком, copysign(1.0, -0.0) возвращает -1.0.

>>> import math
>>> math.copysign(1, -0.0)
-1.0
>>> math.copysign(1, 0.0)
1.0
person Alex Trebek    schedule 16.08.2014
comment
numpy также имеет копию. Ура! - person The Unfun Cat; 18.06.2018

Да, есть разница между 0,0 и -0,0 (хотя Python не позволяет мне воспроизвести это: -P). Если вы разделите положительное число на 0,0, вы получите положительную бесконечность; если вы разделите это же число на -0,0, вы получите отрицательную бесконечность.

Однако помимо этого практической разницы между двумя значениями нет.

person Chris Jester-Young    schedule 03.11.2010
comment
Вы не можете разделить на 0. Если вы говорите о пределах, -0 имеет еще меньше смысла. - person Falmarri; 03.11.2010
comment
-1 Вы не можете разделить число 0, так как получите ZeroDivisonError. Значит, разницы нет. - person Dominic K; 03.11.2010
comment
@Falmarri: В Python вы не можете; на других языках вы вполне можете. Я обращался к различию между 0,0 и -0,0 в общем смысле обработки с плавающей запятой. - person Chris Jester-Young; 03.11.2010
comment
@ Chris: Но это вопрос о Python. В любом случае почти все языки вызывают ошибку. - person Dominic K; 03.11.2010
comment
@DMan: Почти все языки? Вы, конечно, шутите. Попробуйте использовать следующие выражения в JavaScript и Ruby: 1/0.0, 1/-0.0. - person Chris Jester-Young; 03.11.2010
comment
+1, чтобы отменить голоса против. Крис прав в том, что, например, в C деление с плавающей запятой на 0,0 определено для получения бесконечности со знаком (числитель и знаменатель имеют одинаковый знак)? позитивный негативный. - person AlcubierreDrive; 03.11.2010
comment
@ Chris: Это всего два языка. Позвольте мне поддержать C # и Python. - person Dominic K; 03.11.2010
comment
@DMan: Суть моего сообщения такова: поддержка бесконечности встроена в большинство процессоров с плавающей запятой. Запрещение деления на ноль не является бесплатным, но должно быть предусмотрено в языке. Так что, хорошо это или плохо, многие языки просто не беспокоят. Кроме того, слава богу, C # и Python - это не почти все языки и даже не близкие к ним. - person Chris Jester-Young; 03.11.2010
comment
@ Chris: я не говорю, что бесконечность не встроена в большинство процессоров с плавающей запятой, скорее, многие языки имеют тенденцию генерировать исключение, потому что на самом деле нет точки 1) деления на ноль и 2) использования положительного / отрицательная бесконечность в любом случае. И, слава богу, особенно Javascript не является представлением всех языков. Я бы точно не занимался программированием, если бы это было так. - person Dominic K; 03.11.2010
comment
Вы забываете, что ** имеет более высокий приоритет, чем -. (-0.0) ** 0 дает 1.0. - person dan04; 03.11.2010
comment
@ dan04: Точка. (+1) Тогда я верну свой пост и позволю бесконечности стоять на своих собственных бесконечных ногах. ;-) - person Chris Jester-Young; 03.11.2010
comment
@Chris - Думаю, я говорил о математике, а не о том, что языки делают с числами с плавающей запятой. Я бы отказался от голоса, но у вас +4, так что оно выравнивается - person Falmarri; 03.11.2010
comment
@DMan: Стандарт для чисел с плавающей запятой позволяет это. на самом деле нет никакого смысла, ничего не значит, поскольку они определены и стандартизированы. en.wikipedia.org/wiki −0_ (число) Стандарт существует, реализован и определяет эти вещи ясно и полно. - person S.Lott; 03.11.2010
comment
@ S.Lott - Подскажите, пожалуйста, практическое применение деления на ноль - person Dominic K; 04.11.2010
comment
@ S.Lott - Как я уже сказал в своем предыдущем комментарии, я понимаю, что он встроен. Многие языки решают генерировать исключение, потому что нет практического использования деления на ноль и, скорее всего, это ошибка. Пожалуйста, прочтите мой комментарий еще раз. - person Dominic K; 04.11.2010
comment
@ S.Lott: Как я уже сказал в своем предыдущем комментарии, я сказал, что понял, что он встроен (и, следовательно, существует). Так что я никогда не отрицал его существования. Я вообще-то думаю, что вы спорите совсем о другом. Мой аргумент заключался в том, что многие языки создают исключение при делении на ноль, даже если это возможно, потому что это не то, что вы планировали. Похоже, вы уходите от темы. - person Dominic K; 04.11.2010
comment
@ S.Lott - Вы не можете разделить число 0, так как получите ZeroDivisonError. Значит, разницы нет. Истинный. Поскольку делить на ноль нельзя, видимой разницы нет. на самом деле нет никакой точки 1) деления на ноль и 2) использования положительной / отрицательной бесконечности. Истинный. Пожалуйста, напишите для меня полезный фрагмент кода, который делит на ноль и использует положительную бесконечность. Вы этого не сделаете. Определены стандартные или нет, они просто бесполезны. Это все. - person Dominic K; 04.11.2010
comment
@ S.Lott: Понимание после третьего раза тоже полезно. - person Dominic K; 04.11.2010
comment
@ S.Lott: Я также понимаю, что стандарт определяет положительную / отрицательную бесконечность. Я просто не понимаю, почему это важно. - person Dominic K; 04.11.2010
comment
@DMan: Важно, чтобы (а) они существовали и (б) существовала реализация. (Даже если оно частичное.) Потому что вы (и я) не понимаете сложных математических тонкостей, это ничего не значит. Они все еще существуют. Я не разбираюсь в уравнениях в частных производных и не вижу практической ценности. Некоторые люди так делают. Я вижу в стандарте ограниченную практическую ценность. Не в этом дело. Мое скромное мнение о практичности не имеет смысла. Он по-прежнему существует, имеет значение и частично реализован. - person S.Lott; 05.11.2010
comment
@ S.Lott: Я не понимаю, к чему вы клоните. - person Dominic K; 05.11.2010
comment
@ S.Lott: Спасибо за уточнение. Поскольку это становится довольно длинной строкой комментариев, я просто скажу, что я сохраню свою точку зрения, а вы можете сохранить свою. - person Dominic K; 05.11.2010
comment
@DMan Вам нужно деление на ± 0,0, потому что число с плавающей запятой +0.0 не представляет собой математический 0. Оно представляет собой диапазон чисел, близкий к 0. Арифметическое опустошение - это один из способов получить значение +0.0 без математического достижения 0. - person leewz; 23.04.2018
comment
У меня была открыта непрочитанная вкладка о назначении нулей со знаком: softwareengineering.stackexchange.com/questions/280648/ - person leewz; 23.04.2018

Те же значения, но разные числа

>>> Decimal('0').compare(Decimal('-0'))        # Compare value
Decimal('0')                                   # Represents equality

>>> Decimal('0').compare_total(Decimal('-0'))  # Compare using abstract representation
Decimal('1')                                   # Represents a > b

Ссылка:
http://docs.python.org/2/library/decimal.html#decimal.Decimal.compare http://docs.python.org/2/library/decimal.html#decimal.Decimal.compare_total

person user    schedule 14.03.2014