Достижение желаемого результата с помощью fmod или аналогичного, несмотря на арифметику с плавающей запятой

Фон

Рассмотрим проверку трех двойников low, width и high так, чтобы выполнялись следующие три правила:

  1. low < high;
  2. width > 0; и
  3. width вписывается в (high - low) "точно" целое число раз.

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

Например:

(A) low = -0.5, width = 0.005 и high = 0.5

будет указывать диапазон с действительной шириной ячейки, поскольку можно создать «ровно» 200 полных ячеек, тогда как

(B) low = -0.5, width = 0.275 и high = 0.5

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

Проблема

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

Моя первая наивная попытка состояла из:

fmod( high - low, width ) == 0.0

но, к сожалению, fmod возвращает 0,005, например (A) - мой отладчик говорит мне, что двойное значение 0,005 фактически содержит значение 0.0050000000000000001.

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

Это то, что у меня есть на данный момент:

bool valid(double range, double width, double tolerance = 0.000000001)
{
  assert(width > 0 && range > 0);

  while( range > 0 && range > tolerance )
  {
    range -= width;
  }

  return abs(range) <= tolerance;
}

Обратите внимание на полную и абсолютную произвольность значения допуска по умолчанию...


person JimmidyJoo    schedule 19.06.2012    source источник
comment
Почему вы используете двойников? Это приложение, для которого они не особенно хорошо подходят. Почему бы не использовать рациональные числа или фиксированную точку?   -  person David Schwartz    schedule 19.06.2012
comment
Обязательно ли ширина конечного бина гистограммы должна быть меньше, чем у других бинов порядка 10^-10? В конце концов, в природе систем с плавающей запятой у вас будут маленькие нечеткие биты.   -  person Rook    schedule 19.06.2012
comment
@DavidSchwartz - Значения на самом деле вводятся пользователями в графическом интерфейсе и поэтому поступают ко мне в виде строк, которые я мог бы легко преобразовать в то, что я выберу. Возможно, ответ заключается в простом отказе от использования двойников.   -  person JimmidyJoo    schedule 19.06.2012
comment
@Rook - мы используем БПФ дальше по линии, которая требует довольно точных вещей, но этот код не принадлежит мне, поэтому я не уверен, насколько точен. Еще больше усложняет ситуацию то, что код компилируется на Фортране с использованием F2Py, поэтому двойники переходят от C++ к Python и к Фортрану...   -  person JimmidyJoo    schedule 19.06.2012
comment
Мне, вероятно, нужно получить более четкое представление о моих требованиях / проблемном пространстве. Я надеялся на простоту, просто использовать сверхпростую встроенную библиотечную функцию [____], но это было просто глупо.   -  person JimmidyJoo    schedule 19.06.2012


Ответы (1)


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

Если вы знаете свою максимальную точность, умножьте до целых значений для сравнения.

person Jon Cage    schedule 19.06.2012