Округлить число до степени двойки в вверх
От:
menify
Дата: 30.12.02 03:09
Оценка:
Привет!
Можно ли округлить число до степени двойки вверх в одно выражение?
Например:
1 -> 2
2 -> 2
3 -> 4
12 -> 16
15 -> 16
18 -> 32
33 -> 64
и т.д.
пока лучшее, что я придумал
int size_align( int size)
{
register int k;
register int l;
for (k = size; (l = k & (k - 1)) != 0; k = l);
return (size + (k - 1)) & (~(k - 1));
}
Хотелось бы в обойтись без цикла.
Всего доброго.
Re: Округлить число до степени двойки в вверх
Здравствуйте, menify, Вы писали:
M>Привет!
M>Можно ли округлить число до степени двойки вверх в одно выражение?
M>пока лучшее, что я придумал
int size_align( int size)
{
register int k;
register int l;
for (k = size; (l = k & (k - 1)) != 0; k = l);
return (size + (k - 1)) & (~(k - 1));
}
так попроще вроде ...
DWORD size_align( DWORD size)
{
size--;
for (DWORD d=0x80000000; (d & size) == 0 ; d>>=1);
return d<<1;
}
а без цикла, думаю, облизнёшься
Re: Округлить число до степени двойки в вверх
От:
Feunoir
Дата: 30.12.02 07:56
Оценка:
Здравствуйте, menify, Вы писали:
M>Можно ли округлить число до степени двойки вверх в одно выражение?
M>Например:
M>1 -> 2
M>2 -> 2
M>3 -> 4
M>12 -> 16
M>15 -> 16
M>18 -> 32
M>33 -> 64
M>и т.д.
M>пока лучшее, что я придумал
M>Хотелось бы в обойтись без цикла.
size:=1 shl ceil(ln(size)/ln(2));
Только вряд-ли это будет быстрее
... << RSDN@Home 1.0 beta 4 >>
Re: Округлить число до степени двойки в вверх
Здравствуйте, menify, Вы писали:
Вариант 1
Идея такая: нужно найти старший значащий бит, затем проверить, не равно ли наше число 2**номер_бита (случай 2 -> 2), и если нет — увеличить номер.
Искать номер старшего значащего бита можно с помощью бинарного поиска.
Вариант 2
Создать заранее массив степеней двойки, а потом искать в нем:
const int nSize = 32;
std::vector<unsigned int > aPowers(nSize, 0);
for (int i = 1; i < nSize; ++i)
aPowers[i] = aPowers[i-1]*2;
...
int size_align( int size, const std::vector<unsigned int >& aPowers)
{
return *lower_bound(aPowers.begin(), aPowers.end(), size);
}
Итого получаем логарифмическую сложность.
Только надо быть поаккуратнее с преобразованиями unsigned int -> int
Любите книгу — источник знаний (с) М.Горький
Re[2]: Округлить число до степени двойки в вверх
От:
menify
Дата: 30.12.02 08:30
Оценка:
Здравствуйте, Bell, Вы писали:
B>Здравствуйте, menify, Вы писали:
B>Вариант 1
B>Идея такая: нужно найти старший значащий бит, затем проверить, не равно ли наше число 2**номер_бита (случай 2 -> 2), и если нет — увеличить номер.
ИМХО, лучше так
if ((size & (size - 1)) == 0)
{
return size;
}
B>Искать номер старшего значащего бита можно с помощью бинарного поиска.
Скорее всего этот вариант в общем случае по быстрее будет, чем мой вариант.
Хотя мой вариант будет быстрее, если в числе не более 7-8 установленных битов.
Т.е. 00110000 найдет за две итерации.
Бинарный за пять (если число 32-ух битное).
Просто я подумал, если можно легко получить значение для младшего бита:
(size ^ (size - 1)) & size
То и должно быть для старшего...
Всего доброго.
Re: Округлить число до степени двойки в вверх
От:
Atilla
Дата: 30.12.02 08:58
Оценка:
Здравствуйте, menify, Вы писали:
M>Привет!
M>Можно ли округлить число до степени двойки вверх в одно выражение?
Если ввести операцию @, которая расставляет биты в обратном порядке, то кажется так (не будет работать только на нуле):
result=size|@~((@~size)^(@~size+1));
Может кто придумает как реализовать @~ одним Си-шным выражением?..
<< RSDN@Home 1.0 beta 4 >> Blind Guardian — Ashes To Ashes
Кр-ть — с.т.
Re: Округлить число до степени двойки в вверх
От:
Znow
Дата: 30.12.02 09:01
Оценка:
Здравствуйте, menify, Вы писали:
M>Можно ли округлить число до степени двойки вверх в одно выражение?
M>Хотелось бы в обойтись без цикла.
Ну, без цикла — или таблицей, или последовательность if, или так:
unsigned char bin_ceil(unsigned char c)
{
return
(c - 1 |
c >> 1 |
c >> 2 |
c >> 3 |
c >> 4 |
c >> 5 |
c >> 6 |
c >> 7) + 1; // Идея понятна?
}
Re: Округлить число до степени двойки в вверх
От:
Lexey
Дата: 30.12.02 09:14
Оценка:
Здравствуйте, menify, Вы писали:
M>Привет!
M>Можно ли округлить число до степени двойки вверх в одно выражение?
M>Например:
M>1 -> 2
1 — это тоже степень двойки, так что, по идее, дожна оставаться как есть.
M>2 -> 2
M>3 -> 4
M>12 -> 16
M>15 -> 16
M>18 -> 32
M>33 -> 64
M>и т.д.
Вот вариант для чисел 1 < N <= 2**31
return ((N - 1) << 1) & ~(N - 1);
Итого:
return (N == 1) ? 2 : --N, (N << 1) & ~N;
Re[2]: Округлить число до степени двойки в вверх
От:
Lexey
Дата: 30.12.02 09:17
Оценка:
Здравствуйте, Lexey, Вы писали:
L>Вот вариант для чисел 1 < N <= 2**31
L>L>return ((N - 1) << 1) & ~(N - 1);
L>
L>Итого:
L>L>return (N == 1) ? 2 : --N, (N << 1) & ~N;
L>
Блин, опять поторопился. Forget it.
Re: Округлить число до степени двойки в вверх
От:
Chorkov
Дата: 30.12.02 09:38
Оценка:
Здравствуйте, menify, Вы писали:
M>Привет!
M>Можно ли округлить число до степени двойки вверх в одно выражение?
M> ...
Очень длинно, но не более 6 сравнений
long size_align2(long size)
{
if (size <=0)
return 0;
else
if ( size<=0x4000) // 0x1 0x4000
if ( size<=0x40) // 0x1 0x40
if ( size<=0x4) // 0x1 0x4
if ( size<=0x1) // 0x1 0x1
return 0x1;
else // 0x4 0x2
if ( size<=0x2) // 0x2 0x2
return 0x2;
else // 0x4 0x3
return 0x4;
else // 0x40 0x5
if ( size<=0x10) // 0x8 0x10
if ( size<=0x8) // 0x8 0x8
return 0x8;
else // 0x10 0x9
return 0x10;
else // 0x40 0x11
if ( size<=0x20) // 0x20 0x20
return 0x20;
else // 0x40 0x21
return 0x40;
else // 0x4000 0x41
if ( size<=0x400) // 0x80 0x400
if ( size<=0x100) // 0x80 0x100
if ( size<=0x80) // 0x80 0x80
return 0x80;
else // 0x100 0x81
return 0x100;
else // 0x400 0x101
if ( size<=0x200) // 0x200 0x200
return 0x200;
else // 0x400 0x201
return 0x400;
else // 0x4000 0x401
if ( size<=0x1000) // 0x800 0x1000
if ( size<=0x800) // 0x800 0x800
return 0x800;
else // 0x1000 0x801
return 0x1000;
else // 0x4000 0x1001
if ( size<=0x2000) // 0x2000 0x2000
return 0x2000;
else // 0x4000 0x2001
return 0x4000;
else // 0x40000000 0x4001
if ( size<=0x400000) // 0x8000 0x400000
if ( size<=0x40000) // 0x8000 0x40000
if ( size<=0x10000) // 0x8000 0x10000
if ( size<=0x8000) // 0x8000 0x8000
return 0x8000;
else // 0x10000 0x8001
return 0x10000;
else // 0x40000 0x10001
if ( size<=0x20000) // 0x20000 0x20000
return 0x20000;
else // 0x40000 0x20001
return 0x40000;
else // 0x400000 0x40001
if ( size<=0x100000) // 0x80000 0x100000
if ( size<=0x80000) // 0x80000 0x80000
return 0x80000;
else // 0x100000 0x80001
return 0x100000;
else // 0x400000 0x100001
if ( size<=0x200000) // 0x200000 0x200000
return 0x200000;
else // 0x400000 0x200001
return 0x400000;
else // 0x40000000 0x400001
if ( size<=0x4000000) // 0x800000 0x4000000
if ( size<=0x1000000) // 0x800000 0x1000000
if ( size<=0x800000) // 0x800000 0x800000
return 0x800000;
else // 0x1000000 0x800001
return 0x1000000;
else // 0x4000000 0x1000001
if ( size<=0x2000000) // 0x2000000 0x2000000
return 0x2000000;
else // 0x4000000 0x2000001
return 0x4000000;
else // 0x40000000 0x4000001
if ( size<=0x10000000) // 0x8000000 0x10000000
if ( size<=0x8000000) // 0x8000000 0x8000000
return 0x8000000;
else // 0x10000000 0x8000001
return 0x10000000;
else // 0x40000000 0x10000001
if ( size<=0x20000000) // 0x20000000 0x20000000
return 0x20000000;
else // 0x40000000 0x20000001
return 0x40000000;
};
Re[2]: Округлить число до степени двойки в вверх
От:
Кодт
Дата: 30.12.02 11:22
Оценка:
Здравствуйте, Bell, Вы писали:
B>Вариант 2
B>Создать заранее массив степеней двойки, а потом искать в нем:
Только можно обойтись без стд::вектора
template < class N > // беззнаковый!
N highest_bit(N n)
{
const size_t count = sizeof (N) * CHAR_BIT;
static const table[count];
static bool init = false ;
if (!init)
{
size_t i; N b = 1;
for (size_t i = 0; i < count; ++i, b <<= 1) table[i] = b;
init = true ;
}
return *lower_bound(table, table+count, n);
}
Перекуём баги на фичи!
Re: Округлить число до степени двойки в вверх
От:
Аноним
Дата: 10.01.03 12:34
Оценка:
Здравствуйте, menify, Вы писали:
M>Можно ли округлить число до степени двойки вверх в одно выражение?
Log2(Size)=T;
if (T!=(int)T) T++;
return 2^T;
Пока на собственное сообщение не было ответов, его можно удалить.
Удалить