Наиболее общий c способ вычисления среднего значения - PullRequest
0 голосов
/ 06 марта 2020

У меня есть два значения какого-то общего типа c цифра c. Единственное известное, что один меньше другого. Я не знаю, подписаны они или нет, являются ли они целыми числами или числами с плавающей запятой. Мне нужно вычислить значение, которое находится посередине между двумя, так что половина их расстояния. Например, учитывая диапазон [1,11], результат будет 6:

unsigned middle(const unsigned min,const unsigned max)
{
    return (max + min) / 2U;
}

Но пример, конечно, не достаточно c достаточно для всех случаев и для всех типов. Чем я могу заменить это?

1 Ответ

0 голосов
/ 06 марта 2020

Проблема здесь принципиально отличается для целочисленных типов и типов с плавающей точкой. Я предполагаю, что типы с фиксированной точкой, 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, но это редко является проблемой. Только не забывайте об этом в своих тестах.

...