Comments 25
В маркетинге бывает наоборот — попытка собрать информацию ломает коммерческий процесс. Или она так его меняет, что собранная информация обесценивается, полностью или частично.
В приведенном примере видно, что ошибка кроется в прямом сравнении чисел с плавающей точкой, которое нельзя так делать. И этот баг скорее всего можно назвать борбагом.
А нужно как-то так:
bool is_not_equal(double a, double b) {
	return std::fabs(a - b) > std::numeric_limits<double>::epsilon();
}

Можно написать ещё проще:


//current = round(current * 1000.0) / 1000.0;
//cout << current << endl; //<-- COMMENT BACK IN TO "FIX" BUG
} while (fabs(current - last) >= 1e-3);

А round не нужен. Это источник потенциальных ошибок. Например, если результат будет последовательно меняться: 1.0005 + eps, 1.0005 — eps,…, тогда даже если eps будет очень мало, мы никогда не остановимся.

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


std::fabs(a - b) <= std::numeric_limits<T>::epsilon() * std::max(std::abs(a), std::abs(b)) * units_in_the_last_place;
epsilon, обчно величина порядка 1E-7...1E-8 для float, это отклонение МАНТИССЫ числа, а не самого числа.
для применения epsilon нужно сначала отделить порядок от мантиссы, иначе у вас 1E-30 будет равен 1E-20

Продолжая квантовую тему, предлагаю ввести Эверетт-баг: когда код выполняется в какой-то "параллельной Вселенной" и его результаты абсолютно не соотносятся с исходниками. Обычно происходят по причине неправильного билда, либо ввиду внутренних багов используемых библиотек.

Сталкивался :-( ужасные впечатления, после 100500 тестов хочется просто проснуться и чтобы такое больше никогда не снилось.

Ха! Вот только за последние три месяца (специфично для Java):


  1. Пустой catch. Вредитель, писавший бизнес-логику верхнего уровня, замолчал исключение и поставил try с пустым catch. В итоге мы думали, что сбой ниже — в протоколе передачи: данные-то на экране показывались совсем левые, а исключение "типа" не выбрасывалось.
  2. Невозможное поведение на сертификационном вокрбенче. Тестовая группа клиента отправляет нам багрепорты, которые уже давно были пофикшены и на тестах не возникали. Две недели компостировали нам мозги: делаем в коде различные "подпорки" для гипотетических (и невозможных) случаев, добавляем больше логов. В итоге требую доступ к сертификационной машине и вижу — о чудо — определена переменная CLASSPATH и в нее добавлены старые .jar-ы из другой директории...
  3. Пустой-не пустой список. Функция фильтровала значения в списке, но на выход выдавала всегда пустой. Причем на все 100% верная и локально все тесты проходит. А на сервере не выдает. После разделывания кода оказался баг в библиотеке ORM, который выдавал "бажной" IndirectList: https://bugs.eclipse.org/bugs/show_bug.cgi?id=433075
  4. В задеплоенном приложении тупо не работали периодические процессы, а ошибки в логах не было. В результате головной боли обнаружилось, что клиент использовал кривой sftp, который почему-то обрезал концовку файла. А возникавший NoClassDefFoundError не перехватывался catch(Exception e) и поэтому в лог не выводился.
Пункт 1) это вообще какая-то хитроумная диверсия, по-моему. Пункт 2) — ситуация странным образом довольно типичная, полагаю, на нечто подобное попадались (в том или ином варианте) почти все. Пункты 3) и 4) — ну это просто злой рок, никто не застрахован.

Да и ошибки в компиляторах никто не отменял. Уже 2 раза с таким сталкивался.

На PHP сплошь и рядом бывает во всяких нечасто используемых расширениях Особенно, если писать под виндой, а потом разворачивать на Linux-сервере (хотя и с разными версиями Linux случаются нестыковки). Из того что помню — функции для работы с сокетами сильно платформозависимы.
Было такое.
Код
std::timed_mutex mutex;
mutex.lock();
mutex.try_lock_for(std::chrono::seconds(1));
почему-то не ждал, как полагается, секунду для разблокировки мьютекса, а сразу говорил что таймаут истёк и блокировку снять не удалось.
На это была убита почти половина дня, а в итоге выяснилось что это баг в стандартной библиотеке:
gcc.gnu.org/bugzilla/show_bug.cgi?id=54562

А если еще вспомнить описание прекрасной POSIX-функции cuserid() из manpages
Sometimes it does not work at all, because some program messed up the utmp file. Often, it gives only the first 8 characters of the login name.

Nobody knows precisely what cuserid() does; avoid it in portable programs.
У меня такое было. Причём, имело признаки гейзенбага. В итоге оказалось, что прориетарная ОСРВ неполностью сохраняла контекст. Было вылечено по методу «клистир» (перед проблеммным местом запрещались прерывания CLI, п после — разрешались STI.
О даа, «повезло» пару раз словить :( Ну, зато теперь я знаю как это называется :)
Я словил механический гейзенбаг.
Не запускалась стиральная машинка: вместо стирки гудит и выключается. Через неделю работает. А потом нет. Нет стабильности.
Оказалось, в нее вода не поступает. Или поступает — как получится. Тройник между холодной водой для раковины и стиральной машинкой был сделан на основе крана (с крутящейся ручкой), и вода поступает в обе системы только в некоторых положениях крана.
Вот вам костыль в сантехнике.
Ах-ха, как раз сейчас ловим баг в серверном приложении, который дичайше зависит от тайминга и расположения кода. С произвольной перезаписью произвольной памяти.
Буквально втыкаешь немного логгирования — все, либо ошибки нет, либо она проявляется совсем по-другому. И делай что хошь.
Тоже ловил подобную багу (раз уж делимся опытом). В дебаге работает, в релизе иногда клиент падает, если сервер перезапускается, но в релизе с прицеплённым отладчиком всё идеально. Прицепление отладчика после падения приводит к различным местам, связанным с криптографией. Куча времени потрачено на синхронизацию, чистку объектов, а оказалось, что в нативном вызове чуть поменялась структура данных, и она портит память, но так, что стреляет только при таких условиях и совершенно в несвяазанном коде.
И как нашли, кто нашкодил? Это ж самое сложное. Ну вот, упал у тебя поток Х, а данные его попортил поток Y сто лет назад :( Пока ввели искусственные guard page в тех местах, где была порча.
Просто уже предположили, что в таком виде очень похоже на порчу памяти, начали вспоминать, что обновляли (может просто у них глюк?), а там, при вдумчивой проверке структур и обнаружили что поменялись структуры при вызове.
Мы сегодня нашли свою проблему, ура.
Она была в коде 10 лет, и стала проявляться только теперь.
UFO landed and left these words here
Ловил типичный гейзенбаг в начале 90-х, на MSC 6.0 (ещё без плюсов, именно С). Short (16-битный) в стеке параметров занимал стандартные 32 бита. При debug сборке параметр укладывался в одну половину слова, а в release — в другую. Читался при этом он в обоих случаях из одной половины, так что в дебаге всё работало правильно, а в релизе — нет. Ох, долго же я это отлавливал…

О-о-о, было же ещё круче! 5" дискеты. Был 40-дорожечный дисковод, поставили 80-дорожечные. Но у клиентов (за полярным кругом, между прочим), был 40-дорожечный, так что я форматировал под 40 дорожек. И — не работает. То есть там, у них — не работает. У меня — работает. Дискету возят самолётом, программа запускается именно с неё, наличие ложной копии на харде исключено — не было никаких хардов. Привозили, я записывал очередную версию, быстро на следующий самолёт, и — туда. Не работает :-)
… оказалось, что, поскольку «мой» дисковод был 80-дорожечным, в режиме 40 дорожек он писал только на половину ширины дорожки. И у пользователей считывалась старая версия, записанная, ещё когда у меня стоял 40-дорожечный дисковод. Ну, и не работала с новыми данными, ессно.
Разрешилось только, когда я, во-первых, слетал туда в командировку, во-вторых, личную дискету пустил в дело (тогда это было и дорого и дефицитно) — всё заработало сразу. И появилась возможность не спеша анализировать.
Да, история про дискеты просто-таки ностальгичная, несмотря на суровую драматичность сюжета. Какие были времена… (пошёл рыться в шкафу в поисках пятидюймовок с целью выпить водки и над ними всплакнуть).
double a, b;
if (a!=b)
эквивалентно
if( true)
по определению.
Я такие вещи пишу только
if (abs(a-b)<1e-x)
где x — целое больше нуля
Only those users with full accounts are able to leave comments. Log in, please.
Information
Founded

15 September 2008

Location

Россия

Employees

201–500 employees

Registered

12 May 2010