如何确定整数需要多少字节?

我正在寻找最有效的方法来计算存储整数所需的最小字节数而不会丢失精度。

eg int: 10 = 1 byte int: 257 = 2 bytes; int: 18446744073709551615 (UINT64_MAX) = 8 bytes; 

谢谢

PS这是一个哈希函数,将被调用数百万次

字节大小也不必是2的幂

最快的解决方案似乎基于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; } 

与Thomas Pornin的答案相比,使用大多数56位val的速度差异很小(但可测量)。 此外,我没有使用__builtin_clzl测试解决方案,这可以比较。

如果您只对常见尺寸感兴趣,则只需要两个简单的if。 考虑一下(假设您实际上有无符号值):

 if (val < 0x10000) { if (val < 0x100) // 8 bit else // 16 bit } else { if (val < 0x100000000L) // 32 bit else // 64 bit } 

如果您需要测试其他尺寸,选择中间点然后进行嵌套测试将在任何情况下保持测试数量非常低。 但是,在这种情况下,使测试成为递归函数可能是更好的选择,以保持代码简单。 一个不错的编译器将优化掉递归调用,以便生成的代码仍然一样快。

用这个:

 int n = 0; while (x != 0) { x >>= 8; n ++; } 

这假设x包含您的(正)值。

请注意,零将被声明为可编码为无字节。 此外,大多数可变大小的编码需要一些长度字段或终结符来知道编码在文件或流中停止的位置(通常,当您对整数进行编码并考虑大小时,编码对象中有多个整数)。

假设一个字节是8位,为了表示整数x,你需要[log2(x)/ 8] + 1个字节,其中[x] = floor(x)。

好的,我现在看到字节大小不一定是2的幂。 考虑字节大小b。 公式仍为[log2(x)/ b] + 1。

现在,要计算日志,要么使用查找表(速度最快的方式),要么使用二进制搜索,这对于整数来说也非常快。

您可能首先获得最高位集,这与log2(N)相同,然后获取ceil所需的字节数(log2(N)/ 8)。

这里有一些用于获取最高位集的位置,这些位置是从http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogObvious复制的,您可以单击URL以获取有关这些算法的详细信息工作。

查找具有64位IEEE浮点数的整数的整数对数基数2

 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 tu[__FLOAT_WORD_ORDER==LITTLE_ENDIAN] = 0x43300000; tu[__FLOAT_WORD_ORDER!=LITTLE_ENDIAN] = v; td -= 4503599627370496.0; r = (tu[__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]; } 

在O(lg(N))运算中找到N位整数的对数库2

 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; } 

从最重要的一侧( clzbsr )找到第一个’1’位的位置的函数通常是一个简单的CPU指令(不需要弄乱log 2 ),所以你可以将它除以8得到数字需要的字节数。 在gcc中,这个任务有__builtin_clz

 #include  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内在函数 。)

通过取数字的log 2来找到位数,然后除以8得到字节数。

您可以通过以下公式找到x的log n

log n (x)= log(x)/ log(n)

更新:

由于你需要非常快速地完成这项工作, Bit Twiddling Hacks有几种快速计算log 2 (x)的方法。 查找表方法似乎适合您的需求。

这将获得字节数。 它并不是最有效的,但除非你正在编程一个由红细胞所含能量驱动的纳米机器人,否则无关紧要。

 int count = 0; while (numbertotest > 0) { numbertotest >>= 8; count++; } 

如果你需要数组大小,你可以编写一个小模板元编程代码来在编译时弄清楚它:

 template struct NBytes { static const size_t value = NBytes::value+1; }; template<> struct NBytes<0> { static const size_t value = 0; }; int main() { std::cout << "short = " << NBytes::value << " bytes\n"; std::cout << "int = " << NBytes::value << " bytes\n"; std::cout << "long long = " << NBytes::value << " bytes\n"; std::cout << "10 = " << NBytes<10>::value << " bytes\n"; std::cout << "257 = " << NBytes<257>::value << " bytes\n"; return 0; } 

输出:

 short = 2 bytes int = 4 bytes long long = 8 bytes 10 = 1 bytes 257 = 2 bytes 

注意:我知道这不是回答原始问题,但它回答了一个相关的问题,当人们登陆此页面时他们会搜索这个问题。

您需要完全具有日志function

nb_bytes = floor(log(x)/ log(256))+ 1如果你使用log2,log2(256)== 8 so

地板(LOG2(X)/ 8)+1

你需要将256增加到连续的幂,直到结果大于你的值。

例如:(在C#中测试)

 long long limit = 1; int byteCount; for (byteCount = 1; byteCount < 8; byteCount++) { limit *= 256; if (limit > value) break; } 

如果您只希望字节大小为2的幂(如果您不希望65,537返回3),请将byteCount++替换为byteCount *= 2

我认为这是一个简单公式的便携式实现:

 #include  #include  #include  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需要1个字节
 257需要2个字节
 67898需要3个字节
 140000需要3个字节
 2147483647需要4个字节
 -2147483648需要4个字节 

是否以及多少速度和链接浮点库的需要取决于您的需求。

Floor((log2(N)/ 8)+ 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语句。

如果此例程的速度与您所说的一样严格,那么如果您希望将它作为函数调用,则在汇编程序中执行此操作可能是值得的。 这可以让您避免创建和销毁堆栈帧,如果它是关键的话,可以节省一些额外的时钟周期。

对于8次中的每次,将int向右移位8位,看看是否还有1 。 停止前移位的次数是您需要的字节数。

更简洁地说,你需要的最小字节数是ceil(min_bits/8) ,其中min_bits是最高设置位的索引(i+1)

有点基础,但由于输出数量有限,你能否预先计算断点并使用case语句? 无需在运行时进行计算,只需进行有限数量的比较。

为什么不使用32位哈希?

这将在各地以接近最高的速度运行。

我很困惑为什么甚至会想要一个大哈希。 如果一个4字节的哈希工作,为什么不总是使用它? 除了加密用途,谁拥有超过2 32个桶的哈希表呢?

在Sean Anderson的“Bit Twiddling Hacks”页面上有很多很棒的食谱。

我知道这个问题没有要求这种类型的答案,但是对于那些寻找使用最少数量字符的解决方案的人来说,这可以分配给17个字符的长度变量,或25个包括长度变量的声明。

 //Assuming v is the value that is being counted... int l=0; for(;v>>l*8;l++); 

为什么这么复杂? 这就是我想出的:

bytesNeeded = (numBits/8)+((numBits%8) != 0);

如果numBits ,基本上numBits除以8 + 1。

这是基于SoapBox创建一个不包含跳转,分支等的解决方案的想法……不幸的是他的解决方案并不完全正确。 我采用了精神,这里是32位版本,如果需要,可以轻松应用64位检查。

该函数返回存储给定整数所需的字节数。

 unsigned short getBytesNeeded(unsigned int value) { unsigned short c = 0; // 0 => size 1 c |= !!(value & 0xFF00); // 1 => size 2 c |= (!!(value & 0xFF0000)) << 1; // 2 => size 3 c |= (!!(value & 0xFF000000)) << 2; // 4 => size 4 static const int size_table[] = { 1, 2, 3, 3, 4, 4, 4, 4 }; return size_table[c]; } 

这里已经有很多答案,但如果你提前知道数字,在c ++中你可以使用template来使用预处理器。

 template  struct RequiredBytes { enum : int { value = 1 + (N > 255 ? RequiredBits<(N >> 8)>::value : 0) }; }; template <> struct RequiredBytes<0> { enum : int { value = 1 }; }; const int REQUIRED_BYTES_18446744073709551615 = RequiredBytes<18446744073709551615>::value; // 8 

或者位版本:

 template  struct RequiredBits { enum : int { value = 1 + RequiredBits<(N >> 1)>::value }; }; template <> struct RequiredBits<1> { enum : int { value = 1 }; }; template <> struct RequiredBits<0> { enum : int { value = 1 }; }; const int REQUIRED_BITS_42 = RequiredBits<42>::value; // 6 

此代码有0个分支,在某些系统上可能更快。 此外,在某些系统(GPGPU)上,对于同一warp中的线程执行相同的指令非常重要。 无论输入值是什么,此代码始终都是相同数量的指令。

 inline int get_num_bytes(unsigned long long value) // where unsigned long long is the largest integer value on this platform { int size = 1; // starts at 1 sot that 0 will return 1 byte size += !!(value & 0xFF00); size += !!(value & 0xFFFF0000); if (sizeof(unsigned long long) > 4) // every sane compiler will optimize this out { size += !!(value & 0xFFFFFFFF00000000ull); if (sizeof(unsigned long long) > 8) { size += !!(value & 0xFFFFFFFFFFFFFFFF0000000000000000ull); } } static const int size_table[] = { 1, 2, 4, 8, 16 }; return size_table[size]; } 

g ++ -O3生成以下内容(validationifs是否已优化):

 xor %edx,%edx test $0xff00,%edi setne %dl xor %eax,%eax test $0xffff0000,%edi setne %al lea 0x1(%rdx,%rax,1),%eax movabs $0xffffffff00000000,%rdx test %rdx,%rdi setne %dl lea (%rdx,%rax,1),%rax and $0xf,%eax mov _ZZ13get_num_bytesyE10size_table(,%rax,4),%eax retq