Проблема здесь принципиально отличается для целочисленных типов и типов с плавающей точкой. Я предполагаю, что типы с фиксированной точкой, std::complex
и другие менее распространенные числовые типы не нужны.
Для N-разрядных целочисленных типов разница может быть любой между -1 <> N, что это диапазон N + 1 бит. Это решается, когда вы понимаете, что средняя точка (-5, 2) совпадает со средней точкой (2, -5). Следовательно, для целочисленных типов вы можете просто отложить до T middle_impl(std::min<T>, std::max<T>)
. В реализации вам понадобится std::make_unsigned<T>::type
для удержания разницы.
Для чисел с плавающей точкой проблема в основном с ненормальными значениями. Обычно a/2
просто уменьшает экспоненту на единицу, и это точная операция (без округления). Отсюда a+b/2==a/2+b/2
. Но a+b
может быть ненормальным, даже если сами a
и b
не являются. Вы также получаете дополнительную проблему middle(-std::numeric_limits<FP>::infinity(), +std::numeric_limits<FP>::infinity())
, которая должна быть NaN
не ноль. Конечно, все входы NaN должны давать выход NaN, но это редко является проблемой. Только не забывайте об этом в своих тестах.