Выбор значения Эпсилона для сравнений с плавающей точкой
Моя команда работает с финансовым программным обеспечением, которое выставляет денежные значения, когда C# с плавающей запятой удваивается. Иногда нам нужно сравнивать эти значения, чтобы увидеть, равны ли они нулю или не попадают под определенный предел. Когда я заметил неожиданное поведение в этой логике, я быстро узнал об ошибках округления, свойственных двойным числам с плавающей запятой (например, 1.1 + 2.2 = 3.3000000000000003). До этого момента я в основном использовал десятичные числа C# для представления денежных значений.
Моя команда решила решить эту проблему с помощью подхода epsilon value. По сути, когда вы сравниваете два числа, если разница между этими двумя числами меньше, чем эпсилон, они считаются равными. Мы реализовали этот подход аналогичным образом, как описано в статье ниже: https://www.codeproject.com/Articles/383871/Demystify-Csharp-floating-point-equality-and-relat
Нашей задачей было определить подходящее значение для эпсилон. Наши денежные значения могут иметь до 3 цифр справа от десятичной точки (шкала = 3). Это означает, что самый большой эпсилон, который мы могли бы использовать, это.0001 (все, что больше, а третья цифра игнорируется). Поскольку значения epsilon должны быть небольшими, мы решили переместить его еще на одну десятичную точку до.00001 (можно сказать, просто для безопасности). Точность двойных чисел в C# составляет не менее 15 цифр, поэтому я считаю, что это значение эпсилона должно работать, если число слева от десятичной точки меньше или равно 10 цифрам (15 - 5 = 10, где 5 - число Эпсилон цифр находится справа от десятичной точки). С 10 цифрами мы можем представить значения в миллиарды, до 9999999999,999. Вполне возможно, что у нас могут быть цифры в сотни миллионов, но мы не рассчитываем на миллиарды, поэтому этого предела должно быть достаточно.
Правильно ли мое обоснование выбора этого значения эпсилона? Я нашел много ресурсов, которые обсуждают этот подход, но я не мог найти много ресурсов, которые предоставляют рекомендации по выбору эпсилон.
1 ответ
Ваши рассуждения кажутся обоснованными, но, как вы уже обнаружили, это сложный вопрос. Возможно, вы захотите прочитать, что каждый компьютерный ученый должен знать об арифметике с плавающей точкой. У вас есть минимум 15 цифр точности с использованием 64-битных двойных чисел. Однако вы также захотите проверить свои входные данные, так как числа с плавающей запятой могут содержать Nan, +/- Infinity, отрицательный ноль и значительно больший "диапазон", чем 15 десятичных цифр. Если кто-то передает вашей библиотеке значение, например 1.2E102, вы должны обработать его или считать его вне диапазона? То же самое с очень маленькими значениями. Garbage In, Garbage out, но было бы неплохо, если бы ваш код обнаружил "запах" мусора и, по крайней мере, зарегистрировал его.
Вы также можете рассмотреть возможность предоставления свойства для установки точности, а также различных форм округления. Это во многом зависит от спецификаций, с которыми вы работаете. Вы также можете определить, могут ли эти значения представлять валюты, отличные от долларов (1 доллар в настоящее время>112 иен).
Короче говоря, если вы выберете свой эпсилон на цифру ниже своих потребностей (так, что четыре цифры справа от десятичной дроби), то это правильно и дает вам цифру, которую можно использовать для последовательного округления. В противном случае $10.0129 и $10.0121 были бы равны, но их сумма была бы $20.025, а не $20.024 ... бухгалтерам нравятся вещи, которые "ступают".