Почему я должен использовать дополнение 2 для сравнения двух двойных чисел вместо сравнения их различий со значением эпсилона? - PullRequest
3 голосов
/ 18 сентября 2008

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


Обновление: Я просто ищу теоретическую причину, по которой вы бы использовали один над другим. Я всегда использовал метод эпсилон.

Кто-нибудь успешно использовал сравнение 2-х комплементов? Зачем? Почему нет?

Ответы [ 6 ]

3 голосов
/ 18 сентября 2008

вторая ссылка, на которую вы ссылаетесь, упоминает статью с довольно длинным описанием проблемы:

http://www.cygnus -software.com / документы / comparingfloats / comparingfloats.htm

но если вы не настраиваете производительность, я бы использовал epsilon, чтобы люди могли отлаживать ваш код

2 голосов
/ 18 сентября 2008

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

2 голосов
/ 18 сентября 2008

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

Например:

Что такое хороший эпсилон при сравнении расстояния в милях от Атланты, штат Джорджия, Далласа и некоторых других мест в Огайо?

Что такое хороший эпсилон при сравнении расстояния в километрах между моей левой ногой, правой ногой и компьютером под моим столом?

EDIT:

Хорошо, у меня довольно много людей, не понимающих, почему вы не знаете, какой у вас эпсилон.

В давние времена я написал две программы, которые работали с NeverWinter Nights (игрой, созданной BioWare). Одна из программ взяла бинарную модель и преобразовала ее в ASCII. Другая программа взяла модель ASCII и скомпилировала ее в двоичный файл. Один из тестов, которые я написал, состоял в том, чтобы взять все двоичные модели BioWare, декомпилировать их в ASCII и затем вернуться в двоичные. Затем я сравнил свою бинарную версию с оригинальной от BioWare. Одной из проблем во время сравнения была небольшая разница в значениях с плавающей запятой. Поэтому вместо того, чтобы придумывать кучу разных EPSILONS для каждого типа числа с плавающей запятой (вершина, нормаль и т. Д.), Я хотел использовать что-то вроде сравнения двух комплиментов. Таким образом, избегая многократной проблемы EPSILON.

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

EDIT:

LOL, за это проголосовали разные люди.

Я сведу проблему к этому, учитывая два произвольных чисел с плавающей точкой, как вы решаете, какой эпсилон использовать? Ты не можешь

Как вы можете сравнить 1e23 и 1.0001e23 с эпсилоном и все же сравнить 1e-23 и 5.2e-23, используя один и тот же эпсилон? Конечно, вы можете делать некоторые динамические трюки с эпсилонами, но в этом весь смысл сравнения целых чисел (которое НЕ требует, чтобы целые числа были точными).

Целочисленное сравнение позволяет сравнивать два числа с плавающей запятой, используя эпсилон относительно величины чисел.

EDIT

Стив, давайте посмотрим на то, что вы сказали в комментариях:

"Но вы знаете, что для вас значит равенство ... Следовательно, вы должны быть в состоянии найти подходящий эпсилон".

Переверните это утверждение, чтобы сказать:

«Если вы знаете, что для вас значит равенство, тогда вы сможете найти подходящий эпсилон».

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

0 голосов
/ 19 сентября 2008

Использование любого метода, который выполняет побитовое сравнение, приведет к проблемам, когда дроби представлены в виде приближений. Все числа с плавающей точкой с дробями, которые не выражены в степенях два (1/2, 1/4, 1/8, 1/65536 и т. Д.), Являются приблизительными. Так что, конечно, все иррациональные числа.

плавающий третий = 1/3; float two = 2.0; float another_two = третий * 6,0; если (два! = another_two) print ("Приближение! \ n");

Единственное время, в которое можно сравнить побитовое сравнение, будет работать, когда вы выводите числа с плавающей запятой совершенно одинаковым образом или они являются точными представлениями (целые числа, дробные степени двух). Даже тогда может быть несколько представлений некоторых чисел, хотя я никогда не видел этого в работающей системе.

0 голосов
/ 19 сентября 2008

Оскар прав. Не связывайтесь с этим, если вам действительно не нужна эта производительность.

А ты нет. Если бы вы оказались в такой ситуации, вам бы не пришлось задавать вопрос - вы бы уже знали. Если вы так думаете, значит, нет. Ваши проблемы с производительностью лежат в другом месте. Просто используйте читаемую версию.

0 голосов
/ 19 сентября 2008

Когда дело доходит до скорости, соблюдайте следующие правила:

  1. Если вы не очень опытный разработчик, не оптимизируйте.
  2. Если вы опытный разработчик, пока не оптимизируйте.

Сделай самый простой способ.

Alex

...