Я ищу самый эффективный способ вычислить, минимальное число байтов должно было сохранить целое число, не теряя точность.
e.g.
int: 10 = 1 byte
int: 257 = 2 bytes;
int: 18446744073709551615 (UINT64_MAX) = 8 bytes;
Спасибо
P.S. Это для хеш-функции, которые назовут многими миллионами времен
Также размеры байта не должны быть питанием два
Быстрое решение кажется одному на основе ответа tronics:
int bytes;
if (hash <= UINT32_MAX)
{
if (hash < 16777216U)
{
if (hash <= UINT16_MAX)
{
if (hash <= UINT8_MAX) bytes = 1;
else bytes = 2;
}
else bytes = 3;
}
else bytes = 4;
}
else if (hash <= UINT64_MAX)
{
if (hash < 72057594000000000ULL)
{
if (hash < 281474976710656ULL)
{
if (hash < 1099511627776ULL) bytes = 5;
else bytes = 6;
}
else bytes = 7;
}
else bytes = 8;
}
Разность оборотов, использующая главным образом 56 битов vals, была минимальна (но измерима) по сравнению с ответом Thomas Pornin. Также я не протестировал использование решения __ builtin_clzl, который мог быть сопоставимым.
Вам нужно всего два простых if
s, если вас интересуют только общие размеры. Рассмотрим следующее (если предположить, что у вас действительно есть беззнаковые значения):
if (val < 0x10000) {
if (val < 0x100) // 8 bit
else // 16 bit
} else {
if (val < 0x100000000L) // 32 bit
else // 64 bit
}
Если вам нужно проверить другие размеры, выбор средней точки и последующее выполнение вложенных тестов в любом случае уменьшит количество тестов. Однако в этом случае лучшим вариантом будет сделать тестирование рекурсивной функцией, чтобы сохранить простоту кода. Приличный компилятор оптимизирует рекурсивные вызовы так, что результирующий код будет все таким же быстрым.
Для каждого из восьми раз сдвиньте int на восемь бит вправо и посмотрите, осталось ли еще 1
-битов. Количество раз, которое вы сдвигаете перед остановкой, - это количество байтов, которое вам нужно.
Более кратко, минимальное количество байтов, которое вам нужно, составляет ceil (min_bits / 8)
, где min_bits
- это индекс (i + 1)
из самый высокий установленный бит.
Есть множество способов сделать это.
Вариант №1.
int numBytes = 0;
do {
numBytes++;
} while (i >>= 8);
return (numBytes);
В приведенном выше примере это число, которое вы тестируете, и обычно оно работает для любого процессора, любого размера целого числа.
Однако он может быть не самым быстрым. В качестве альтернативы вы можете попробовать серию операторов if ...
Для 32-битных целых чисел
if ((upper = (value >> 16)) == 0) {
/* Bit in lower 16 bits may be set. */
if ((high = (value >> 8)) == 0) {
return (1);
}
return (2);
}
/* Bit in upper 16 bits is set */
if ((high = (upper >> 8)) == 0) {
return (3);
}
return (4);
Для 64-битных целых чисел потребуется другой уровень операторов if.
Если скорость этой процедуры настолько критична, как вы говорите, возможно, стоит сделать это на ассемблере, если вы хотите, чтобы это было вызовом функции. Это может позволить вам избежать создания и уничтожения кадра стека, сэкономив несколько дополнительных тактовых циклов, если это так важно.
Floor ((log2 (N )/8) + 1) байт
-121--1466486- .Net содержит список допустимых типов постоянных ссылок, StringBuilder
не является одним из них.
Претензия заключается в том, что то, что вы создаете, не является незыблемым, хотя статический конструктор вызывается один раз и класс инициализируется один раз, это все, что остается прежним, остальное может изменяться. Один поток может вызвать .Append ()
, затем другой... вы видите, как последовательность builder сам мутирует и на самом деле не только для чтения
, потому что он постоянно меняет состояния/мутирует.
Объявление только для чтения
действительно является неправильным, поскольку сам объект, на который имеется ссылка, постоянно изменяется.
Вам нужна именно функция log
nb _ bytes = floor (log (x )/регистрация (256)) + 1 если используется log2, log2 (256) = = 8 so
floor (log2 (x )/8) + 1
Это даст вам количество байтов. Строго говоря, это не самый эффективный вариант, но если вы не программируете наноробота, работающего на энергии, содержащейся в эритроците, это не имеет значения.
int count = 0;
while (numbertotest > 0)
{
numbertotest >>= 8;
count++;
}
Найдите количество битов, взяв логарифм 2 числа, затем разделите его на 8, чтобы получить количество байтов.
Вы можете найти журнал n x по формуле:
log n (x) = log (x) / log (n)
Поскольку вам нужно сделать это очень быстро, Bit Twiddling Hacks имеет несколько методов для быстрого вычисления журнала 2 (x). Подход с использованием таблицы поиска, кажется, соответствует вашим потребностям.
на странице "Bit Twiddling Hacks" Шона Андерсона есть много отличных рецептов для подобных вещей.
Я бы подумал, что если имя схемы в конечном итоге совпадает со схемой базы данных, то вы просто добавляете избыточность в базу данных. Найдите в базе данных объекты, имеющие общую область или назначение, и создайте схему, чтобы отразить эту область. Так, например, если у вас есть сущность для счетов-фактур, и у вас есть некоторые поддерживающие таблицы поиска для состояний счетов-фактур и т.д., то поместите их все в схему счетов-фактур.
Как правило, я бы постарался избежать использования имени, которое отражает имя приложения, имя базы данных или другие конкретные/физические вещи, потому что они могут изменяться, и найти имя, которое концептуально представляет область ваших объектов, которые войдут в схему.
В вашем комментарии говорится, что "схемы будут в значительной степени использоваться для простого назначения разрешений ролям". На диаграмме показаны определенные типы пользователей, имеющие доступ к некоторым/всем таблицам или к некоторым/всем хранимым процессам. Я думаю, что попытки организовать объекты концептуально в схемы и организовать их с точки зрения безопасности в схемы являются противоречивыми вещами. Я выступаю за создание ролей в SQL Server для отражения типов пользователей и предоставление этим ролям доступа к конкретным объектам, которые необходимы каждому типу пользователя, в соответствии с предоставлением роли или доступа пользователя к схеме для построения инфраструктуры безопасности.
-121--4817549- необходимо использовать android: singleLine = "false"
в тегах ur TextView
.
Это будет работать с почти максимальной скоростью везде.
Я довольно запутался в том, почему большой хеш был бы даже нужен. Если работает 4-байтовый хеш, почему бы не использовать его всегда? За исключением криптографических приложений, кто имеет хэш-таблицы с более чем 2 32 ведрами?
Немного просто, но поскольку количество выходов ограничено, нельзя ли предварительно вычислить точки останова и использовать оператор case? Нет необходимости в вычислениях во время выполнения, только ограниченное количество сравнений.
Вам нужно возвести 256 в последовательные степени, пока результат не станет больше вашего значения.
Например: (Протестировано на C #)
long long limit = 1;
int byteCount;
for (byteCount = 1; byteCount < 8; byteCount++) {
limit *= 256;
if (limit > value)
break;
}
Если вы хотите, чтобы размеры байтов были степенями двойки (если вы не хотите, чтобы 65 537 возвращали 3), замените byteCount ++
на byteCount * = 2
.
Вы можете написать небольшой шаблонный метапрограммный код, чтобы выяснить это во время компиляции, если он вам нужен для размеров массивов:
template<unsigned long long N> struct NBytes
{ static const size_t value = NBytes<N/256>::value+1; };
template<> struct NBytes<0>
{ static const size_t value = 0; };
int main()
{
std::cout << "short = " << NBytes<SHRT_MAX>::value << " bytes\n";
std::cout << "int = " << NBytes<INT_MAX>::value << " bytes\n";
std::cout << "long long = " << NBytes<ULLONG_MAX>::value << " bytes\n";
std::cout << "10 = " << NBytes<10>::value << " bytes\n";
std::cout << "257 = " << NBytes<257>::value << " bytes\n";
return 0;
}
output:
short = 2 bytes
int = 4 bytes
long long = 8 bytes
10 = 1 bytes
257 = 2 bytes
Примечание. Я знаю, что это не ответ на исходный вопрос, но он отвечает на связанный вопрос, который люди будут искать, когда попадут на эту страницу.
Вы можете сначала получить самый высокий набор битов, который совпадает с log2 (N), а затем получить байты, необходимые для ceil (log2 (N) / 8).
Вот несколько хитростей для получения позиции самого высокого набора битов, которые скопированы из http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogObvious , и вы можете щелкните URL-адрес, чтобы узнать, как работают эти алгоритмы.
Найти логарифмическую базу 2 целого числа с помощью 64-битного числа с плавающей запятой IEEE
int v; // 32-bit integer to find the log base 2 of
int r; // result of log_2(v) goes here
union { unsigned int u[2]; double d; } t; // temp
t.u[__FLOAT_WORD_ORDER==LITTLE_ENDIAN] = 0x43300000;
t.u[__FLOAT_WORD_ORDER!=LITTLE_ENDIAN] = v;
t.d -= 4503599627370496.0;
r = (t.u[__FLOAT_WORD_ORDER==LITTLE_ENDIAN] >> 20) - 0x3FF;
Найти логарифмическую базу 2 целого числа с помощью таблицы поиска
static const char LogTable256[256] =
{
#define LT(n) n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n
-1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
LT(4), LT(5), LT(5), LT(6), LT(6), LT(6), LT(6),
LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7)
};
unsigned int v; // 32-bit word to find the log of
unsigned r; // r will be lg(v)
register unsigned int t, tt; // temporaries
if (tt = v >> 16)
{
r = (t = tt >> 8) ? 24 + LogTable256[t] : 16 + LogTable256[tt];
}
else
{
r = (t = v >> 8) ? 8 + LogTable256[t] : LogTable256[v];
}
Найти логарифмическую базу 2 N-битного целого числа в O (lg (N)) operations
unsigned int v; // 32-bit value to find the log2 of
const unsigned int b[] = {0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000};
const unsigned int S[] = {1, 2, 4, 8, 16};
int i;
register unsigned int r = 0; // result of log2(v) will go here
for (i = 4; i >= 0; i--) // unroll for speed...
{
if (v & b[i])
{
v >>= S[i];
r |= S[i];
}
}
// OR (IF YOUR CPU BRANCHES SLOWLY):
unsigned int v; // 32-bit value to find the log2 of
register unsigned int r; // result of log2(v) will go here
register unsigned int shift;
r = (v > 0xFFFF) << 4; v >>= r;
shift = (v > 0xFF ) << 3; v >>= shift; r |= shift;
shift = (v > 0xF ) << 2; v >>= shift; r |= shift;
shift = (v > 0x3 ) << 1; v >>= shift; r |= shift;
r |= (v >> 1);
// OR (IF YOU KNOW v IS A POWER OF 2):
unsigned int v; // 32-bit value to find the log2 of
static const unsigned int b[] = {0xAAAAAAAA, 0xCCCCCCCC, 0xF0F0F0F0,
0xFF00FF00, 0xFFFF0000};
register unsigned int r = (v & b[0]) != 0;
for (i = 4; i > 0; i--) // unroll for speed...
{
r |= ((v & b[i]) != 0) << i;
}
Предполагая, что байт - это 8 бит, для представления целого числа x нужно [log2(x) / 8] + 1 байт, где [x] = floor(x).
Хорошо, теперь я вижу, что размер байта не обязательно является степенью двойки. Рассмотрим размеры байтов b. Формула по-прежнему [log2(x) / b] + 1.
Теперь, чтобы вычислить log, используйте либо таблицы поиска (лучший способ с точки зрения скорости), либо двоичный поиск, который также очень быстр для целых чисел.
Я думаю, что это переносимая реализация простой формулы:
#include <limits.h>
#include <math.h>
#include <stdio.h>
int main(void) {
int i;
unsigned int values[] = {10, 257, 67898, 140000, INT_MAX, INT_MIN};
for ( i = 0; i < sizeof(values)/sizeof(values[0]); ++i) {
printf("%d needs %.0f bytes\n",
values[i],
1.0 + floor(log(values[i]) / (M_LN2 * CHAR_BIT))
);
}
return 0;
}
Вывод:
10 needs 1 bytes 257 needs 2 bytes 67898 needs 3 bytes 140000 needs 3 bytes 2147483647 needs 4 bytes -2147483648 needs 4 bytes
Зависит ли и насколько недостаток скорости и необходимость связывания библиотек с плавающей запятой от ваших потребностей.
Функция определения позиции первого бита «1» со стороны старшего разряда ( clz
или bsr
) обычно является простой инструкцией ЦП (не нужно путаться с log 2 ), поэтому вы можете разделить это на 8, чтобы получить количество необходимых байтов. В gcc для этой задачи есть __ builtin_clz
:
#include <limits.h>
int bytes_needed(unsigned long long x) {
int bits_needed = sizeof(x)*CHAR_BIT - __builtin_clzll(x);
if (bits_needed == 0)
return 1;
else
return (bits_needed + 7) / 8;
}
(В MSVC вы должны использовать внутреннюю _BitScanReverse
встроенную .)
Используйте это:
int n = 0;
while (x != 0) {
x >>= 8;
n ++;
}
Это предполагает, что x
содержит ваше (положительное) значение.
Обратите внимание, что ноль будет объявлен кодируемым как отсутствие байта вообще. Кроме того, большинству кодировок переменного размера необходимо некоторое поле длины или терминатор, чтобы знать, где кодирование останавливается в файле или потоке (обычно, когда вы кодируете целое число и думаете о размере, то в вашем кодируемом объекте больше одного целого числа).