2010-10-04 2 views
3

Я хочу сделать «==» оператора использовать приближенное сравнение в моей программе: флоат значения х и у равны (==), еслиприближенное сравнение в питона

abs(x-y)/(0.5(x+y)) < 0.001 

Что хороший способ сделать это? Учитывая, что float является встроенным типом, я не думаю, что могу переопределить оператор ==, не так ли?

Обратите внимание, что я хотел бы использовать другие функции float, единственное, что я хотел бы изменить, - это оператор равенства.

EDIT:

Спасибо за ответы, и я понимаю ваши рассуждения о читаемости и других вопросах.

Было сказано, что я действительно предпочел бы, если возможно, фактически использовать обычный тип float вместо нового класса или новой функции сравнения. Возможно ли переопределить оператор == для регулярных поплавков?

Мои причины ::

(а) все с помощью программы я пишу хочет поплавки можно сравнить этот путь

(б) нет никакого пути в мире, кто бы когда-либо хотели бы используйте default == для floats. Почему это даже на языке ???

(c) Мне не нравятся дополнительные слова в коде; очевидно, используя существующие результаты с плавающей точкой в ​​каких-либо изменений в коде вообще

EDIT 2.

Теперь, когда я знаю, что я не могу перегрузить оператор == для поплавка, я должен изменить свой вопрос. Он станет настолько разные, что я буду делать новую в custom comparison for built-in containers

+1

Удар для воздействия на читаемость, особенно для других. –

+2

Оператор перегрузки '==' кажется симпатичным, но использование отдельной функции для этого почти всегда является лучшей идеей. – Constantin

+0

У меня есть множество сравнений списков чисел (например), которые стали бы намного более запутанными, если бы я не мог переопределить оператор по умолчанию == – max

ответ

7

Ваше определение имеет две проблемы:

  1. Отсутствующие в *

  2. будет пытаться делить на ноль, если x + y == 0.0 (который покрывает возможно частый случай x == y == 0.0)

Try это вместо:

define approx_Equal(x, y, tolerance=0.001): 
    return abs(x-y) <= 0.5 * tolerance * (x + y) 

Редактировать: Обратите внимание, что использование <= вместо < ... необходимо для правильной работы корпуса x == y == 0.0.

Я бы не попытаться переопределить ==

Edit 2: Вы писали:

нет никакого пути в мире, кто бы когда-либо хотели бы использовать по умолчанию == для поплавков .. Почему это даже на языке ???

Ни в коем случае? Предположим, что у вас есть функция, которая возвращает float, и у вас есть мозговая волна об алгоритме, который бы быстрее и точнее выдавал одни и те же ответы; как вы его протестируете?

+0

Одна из причин моего вопроса заключается в том, что я часто сравниваю словари, которые имеют значения разных типов, включая float. Стандартный оператор Python == отлично работает, за исключением float (который нужно сравнивать примерно).Очевидно, что есть простой способ сделать это с помощью некоторого дополнительного кода, но я надеялся, что переопределение == в float будет самым чистым, самым элегантным решением. – max

+0

Я принимаю этот ответ, потому что работа с пользовательским подклассом float ужасно неудобна в Python по причинам, указанным в комментариях к этому решению. Помимо подкласса, это первое правильное решение. – max

+0

Если вы можете переопределить float ==, чтобы избежать чрезвычайной катастрофы, вам нужно было бы переопределить остальные 5 реляционных операторов согласованным образом. Переопределение было бы эффективным для всего кода библиотеки, который не ожидал бы этого. Например. сортировка списка поплавков может не дать тот же ответ. Все ад может сломаться. Усилия, направленные на то, чтобы доказать, что это не вызовет катастрофы, было бы серьезным делом. –

3

Если вы заключаете число в классе вы можете перегрузить «==» с:

def __eq__(self, x): 
    return abs(x - self.x)/(0.5 * (x + self.x)) < 0.001 

однако вы должны переписать выражение

abs(x - self.x) < 0.0005 * (x + self.x)

, чтобы избежать деления на ноль.

+0

Аргументы не кажутся правильными. http://docs.python.org/reference/datamodel.html#object.__eq__ – livibetter

+0

Обязательно укажите также __ne__, чтобы у вас не было и == b, и a! = b true. И имейте в виду, что с __eq__, переопределенным, как указано выше, вы можете иметь и == b и a

+0

livibetter. Извините, что я получил информацию от http://docs.python.org/library/operator.html – MdaG

18

Вы можете создать новый класс, производный от встроенного типа поплавка, а затем перезаписать необходимые операторы:

class InexactFloat(float): 
    def __eq__(self, other): 
     try: 
      return abs(self.real - other)/(0.5 * (abs(self.real) + abs(other))) < 0.001 
     except ZeroDivisionError: 
      # Could do another inexact comparison here, this is just an example: 
      return self.real == other 

    def __ne__(self, other): 
     return not self.__eq__(other) 

print 5.2 == 5.20000000000001 # False 
print 5.2 != 5.20000000000001 # True 
print InexactFloat(5.2) == InexactFloat(5.20000000000001) # True 
print InexactFloat(5.2) != InexactFloat(5.20000000000001) # False 
print InexactFloat(-5) == -5 # True 

# Works for InexactFloat <-> float comparison 
print 5.0 == InexactFloat(5.0) # True 
print InexactFloat(5.0) == 5.0 # True 

# Zero division case (note how I implemented it above!) 
print InexactFloat(-0.00001) == InexactFloat(0.00001) # False 
print InexactFloat(-0.000000001) == InexactFloat(0.000000001) # False 
print InexactFloat(-5) == InexactFloat(5) # False 

# Unit test for fixed negative numbers problem 
print InexactFloat(-5) == InexactFloat(-10) # False 

Вы также можете перезаписать операторы, такие как < = и т.д.

+0

+1: Я думаю, что это лучшая идея - создание нового класса вместо переопределения встроенных операторов для встроенных классов. Но вы все равно должны обрабатывать 'ZeroDivisionError', если оба числа равны или равны нулю. –

+0

@Tim Pietzcker: Верно, я забыл об этом случае. Изменено для соответствующего кода. – AndiDog

+1

@AndiDog: На какой стадии он переключается с использования float на использование этого класса? Нужно ли ему обертывать 'InexactFloat()' вокруг каждого поплавка? Предположим, что он этого не делает, но делает все свои вычисления в поплавках и получает два значения a и b ... ему нужно делать 'InexactFloat (a) == InexactFloat (b)' или он может уйти с 'InexactFloat (a) == b'? Если последний, зачем ему вообще нужен класс? –

Смежные вопросы