Я уже реализовал следующее:
Код: Выделить всё
template
static constexpr T round_pow2(T v) {
if constexpr (std::is_floating_point_v) {
auto high = static_cast(std::ceil(v));
auto low = static_cast(std::floor(v));
if (high == low) {
return round_pow2(high);
} else {
T a = static_cast(round_pow2(low));
T b = static_cast(round_pow2(high));
return std::abs(a - v) > i;
}
high += 1;
T low = high >> 1;
return (high - v) < (v - low) ? high : low;
}
}
Изменения:
@Eric для моего приложения, получение 0 нормально в случае v == 0. Но это может для некоторых действительно может быть проблемой, потому что 0 не является степенью 2.
@Blixodus Спасибо за ваш ответ, он указал мне в правильном направлении. Учитывая вашу идею, я создал следующую функцию:
Код: Выделить всё
template
constexpr T round_p2(T v) {
if constexpr (std::is_floating_point_v) {
using R = std::conditional_t<
std::is_same_v, uint64_t,
std::conditional_t>;
auto [mlen, es, em] = std::is_same_v ? std::make_tuple(52, 1024, 0x7FF) : std::make_tuple(23, 128, 0xFF);
auto y = *reinterpret_cast(&v);
return (T(y >> (sizeof(R) * 8 - 1)) * -2 + 1) * (2 > mlen) & em) - es + ((y >> mlen - 1) & 0x1)));
} else {
using R = std::make_unsigned_t;
R rv = static_cast(v);
T sign = 1;
if constexpr (std::is_signed_v) {
if (v < 0) {
rv = static_cast(-v);
sign = -1;
}
}
R high = rv - 1;
for (R i = 1; i < static_cast(sizeof(R)); i *= 2) {
high |= high >> i;
}
high += 1;
R low = high >> 1;
return sign * static_cast((high - rv) > (sizeof(R) * 8 - 1)) * -2 + 1). При этом извлекается старший бит значения fp (знак: 0 для положительного значения и 1 для отрицательного), а затем применяется к нему функция f(x) = x * -2 + 1, что дает 1 для x=0 и -1 для x=1.
В конце концов я вычисляю ближайшую беззнаковую степень двух из заданных значение fp по формуле Бликсодуса. Потому что я не использую функцию std::pow в пользу битового сдвига (потому что мы работаем со степенями двойки). Мне нужно это учесть, удалив единицу из значения, на которое мы сдвигаем 2 (следовательно, значение es на 1 больше, чем ожидалось).
Подробнее здесь: [url]https://stackoverflow.com/questions/76587725/round-a-floating-point-value-to-the-nearest-power-of-two[/url]