C++ 如何确定一个整数需要多少字节?

C++ 如何确定一个整数需要多少字节?,c++,c,C++,C,我正在寻找一种最有效的方法来计算存储整数所需的最小字节数,而不会丢失精度 e.g. int: 10 = 1 byte int: 257 = 2 bytes; int: 18446744073709551615 (UINT64_MAX) = 8 bytes; 谢谢 另外,这是一个哈希函数,它将被调用数百万次 此外,字节大小不必是2的幂 最快的解决方案似乎是基于tronics的答案: int bytes; if (hash <= UINT32_MAX) {

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

e.g.

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

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

此外,字节大小不必是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;
    }
int字节;

如果(hash,则需要将256次幂提高到连续幂,直到结果大于您的值

例如:(在C#中测试)

long-long-limit=1;
int字节数;
for(字节计数=1;字节计数<8;字节计数++){
极限*=256;
如果(限制>值)
打破
}

<如果你只想字节大小为两个幂(如果你不希望65537返回3),则替换<代码> BytCeNt++/<代码> <代码> BytCeNtt*= 2 .< /P> < P>你只需要两个简单的<代码>如果 s,如果你只对普通大小感兴趣。考虑这个(假设你真的有未签名的值):

if(val<0x10000){
if(val<0x100)//8位
else//16位
}否则{
if(val<0x10000000L)//32位
else//64位
}

如果您需要测试其他大小,选择一个中间点,然后进行嵌套测试将使测试数量在任何情况下都非常少。但是,在这种情况下,使测试成为递归函数可能是一个更好的选择,以保持代码简单。一个好的编译器将优化递归调用,从而使生成的代码更简单直到同样快。

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

OK,我现在看到字节大小不一定是两个幂。考虑字节大小B。公式仍然是[Log2(x)/b] + 1。< /p>


现在,要计算日志,可以使用查找表(最好的速度方式)或二进制搜索,这对整数也很快。

这将得到字节数。严格来说,这不是最有效的,但除非你正在编程一个由红血球中所含能量驱动的纳米机器人,否则这无关紧要

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

对于八次中的每一次,将int八位向右移位,然后查看是否还有
1
-位剩余。停止之前的移位次数就是所需的字节数


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

Floor((log2(N)/8)+1)字节

您需要的正是log函数

nb_字节=地板(对数(x)/对数(256))+1 如果使用log2,那么log2(256)==8


floor(log2(x)/8)+1

通过获取数字的log2来找到位数,然后将其除以8得到字节数

您可以通过以下公式找到x的logn:

对数n(x)=对数(x)/对数(n)

更新: 由于您需要非常快速地执行此操作,因此有几种快速计算log2(x)的方法。查找表方法似乎适合您的需要。

使用以下方法:

int n = 0;
while (x != 0) {
    x >>= 8;
    n ++;
}
这假设
x
包含您的(正)值


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

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

下面是一些用于获取最高位集位置的位破解,这些位集是从中复制的,您可以单击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

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];
}
在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;
}
unsigned int v;//用于查找
常量无符号整数b[]={0x2,0xC,0xF0,0xFF00,0xFFFF0000};
常量无符号整数S[]={1,2,4,8,16};
int i;
register unsigned int r=0;//log2(v)的结果将转到此处
对于(i=4;i>=0;i--)//展开以获得速度。。。
{
如果(v&b[i])
{
v>>=S[i];
r |=S[i];
} 
}
//或者(如果CPU分支缓慢):
unsigned int v;//用于查找的log2的32位值
register unsigned int r;//log2(v)的结果将转到此处
寄存器无符号整数移位;
r=(v>0xFFFF)>=r;
移位=(v>0xFF)>=移位;r |=移位;
移位=(v>0xF)>=移位;r |=移位;
移位=(v>0x3)>=移位;r |=移位;
r |=(v>>1);
//或者(如果你知道v是2的幂):
unsigned int v;//用于查找的log2的32位值
静态常量unsigned int b[]={0xAAAAAAAA,0xcccccc,0xf0f0f0,
0xFF00FF00,0xFFFF0000};
寄存器无符号整数r=(v&b[0])!=0;
对于(i=4;i>0;i--)//展开以获得速度。。。
{

r |=((v&b[i])!=0)我认为这是一个简单公式的可移植实现:

#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;
}
#包括
#包括
#包括
内部主(空){
int i;
无符号int值[]={102576789814000,int_MAX,int_MIN};
对于(i=0;i
输出:

10 needs 1 bytes 257 needs 2 bytes 67898 needs 3 bytes 140000 needs 3 bytes 2147483647 needs 4 bytes -2147483648 needs 4 bytes 10需要1个字节 257需要2个字节 67898需要3个字节 140000需要3个字节 2147483647需要4个字节 -2147483648需要4个字节
是否以及在多大程度上缺乏速度和需要链接浮点库取决于您的需要。

有多种方法可以做到这一点

选项1

在上面的示例中,是您正在测试的数字,通常适用于
#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
 int numBytes = 0;
 do {
     numBytes++;
 } while (i >>= 8);
 return (numBytes);
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);
#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;
}
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;
}
short = 2 bytes
int = 4 bytes
long long = 8 bytes
10 = 1 bytes
257 = 2 bytes
//Assuming v is the value that is being counted...
int l=0;
for(;v>>l*8;l++);
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];
}
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
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];
}
template <unsigned long long N>
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 <unsigned long long N>
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