У меня есть библиотека обработки сигналов, которая функционирует по спецификации. Тем не менее, я определил несколько хороших мест для рефакторинга. Я хотел включить модульное тестирование в свой рабочий процесс в течение некоторого времени, и это похоже на хорошую возможность экспериментировать с нетривиальным кодом. Это так, чтобы я мог проверить, что вывод практически идентичен после рефакторинга.
Я экспериментирую с ловить однако в качестве тестовой среды эта деталь может быть неактуальной, поскольку (из того, что я могу собрать) все тестовые структуры зависят от результатов операторов, т.е.
REQUIRE(i_x == 2)
Однако для данных с плавающей запятой требуется некоторая форма проверки границ ошибок. ,
const float target = 2.000f;
const float tolerance = 0.000005f;
const float err = target*tolerance;
REQUIRE( (f_x > target-err) && (f_x < target+err) )
Это быстро выглядело бы ужасно для каждого написанного теста, поэтому я, конечно, мог бы создать (шаблонизированную) глобальную функцию, которая возвращает bool
дано x
, target
а также tolerance
в качестве параметров.
Так ли это делают все остальные? Это лучшая практика или мне не хватает трюка?
Тестирование очень чувствительно к контексту. Тест, который вы предлагаете, проверяет относительную погрешность. По сути, вы утверждаете, что в данной конкретной ситуации:
Вообще, я думаю, что второе утверждение часто безопасно. «Случайные» изменения кода могут привести к огромным различиям по крайней мере в некоторых значениях. Однако могут существовать приложения, которые прекрасно работают с плавающей запятой, и в этом случае небольшие отклонения могут привести к результатам, выходящим за пределы спецификации. Например, предположим, что у вас есть подпрограмма arcsine, которая возвращает результат, немного отличающийся от правильного: возвращается 1 + 2-23 когда правильный результат равен 1. Позже, этот результат, x, используется в выражении, таком как sqrt(1-x*x)
, Это выражение является действительным для всех математически правильных значений арксинуса (для реальных входных данных), но, учитывая x, который немного больше 1, оно пытается получить квадратный корень из отрицательного числа, и возникает ошибка. Таким образом, вы должны решить, подходит ли второе утверждение для вашего приложения.
Первое утверждение более сомнительно. Источники ошибок в арифметике с плавающей точкой не всегда пропорциональны конечному результату. Например, рассмотрим дискретное преобразование Фурье (ДПФ) некоторого входного сигнала. Почти для каждого выходного числа каждый входной номер вносит свою долю. Случайные числа некоторых отдельных выходов будут близки к нулю. Однако ошибки в них могут быть пропорциональны большим числам на входе. Таким образом, применение теста относительной ошибки к таким выходным числам приведет к ложным признакам ошибок. Вместо этого необходимо допустить ошибку, которая каким-то образом масштабируется входными данными.
Других решений пока нет …