Округлить значение с плавающей запятой до ближайшей степени двойкиC++

Программы на C++. Форум разработчиков
Ответить Пред. темаСлед. тема
Anonymous
 Округлить значение с плавающей запятой до ближайшей степени двойки

Сообщение Anonymous »

Хотя на вопрос о том, как найти следующую степень двойки целого числа или числа с плавающей запятой, существует множество ответов, ответов на вопрос о том, как найти ближайшую степень двойки целого числа или числа с плавающей запятой, не так много.
Я уже реализовал следующее:

Код: Выделить всё

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;
}
}
Это должно работать для любого неотрицательного значения fp ниже ULLONG_MAX. Но это не кажется оптимальным. Есть ли лучший (более производительный) способ реализации этой функции?
Изменения:
@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]
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение
  • Получить значение с плавающей запятой после символа £ в строке и привести к значению типа с плавающей запятой [дубликат]
    Anonymous » » в форуме Php
    0 Ответы
    43 Просмотры
    Последнее сообщение Anonymous
  • Как округлить до ближайшей 1000?
    Anonymous » » в форуме C#
    0 Ответы
    13 Просмотры
    Последнее сообщение Anonymous
  • Почему емкость Deque (ArrayDeque) равна степени двойки?
    Anonymous » » в форуме JAVA
    0 Ответы
    21 Просмотры
    Последнее сообщение Anonymous
  • Оптимизирует ли Java деление по степени двойки для битового сдвига?
    Anonymous » » в форуме JAVA
    0 Ответы
    12 Просмотры
    Последнее сообщение Anonymous
  • Нужно ли мне беспокоиться о текстурах, не имеющих степени двойки, в API 16+?
    Anonymous » » в форуме Android
    0 Ответы
    11 Просмотры
    Последнее сообщение Anonymous

Вернуться в «C++»