更快/更简洁的方法来计算存储有符号/无符号整数所需的适当大小?

发布于 2024-08-01 23:22:27 字数 473 浏览 2 评论 0原文

是否有更快的方法(可能是位操作?)来查找给定值的整数所需的大小? 这是我所得到的:

uint_length(Value) ->
if Value < 256 -> 1;
   Value < 65535 -> 2;
   Value < 4294967295 -> 4
end.

sint_length(Value) ->
if Value < 128 andalso Value >= 0 -> 1;
   Value < 32767 andalso Value >= 0 -> 2;
   Value < 2147483647 andalso Value >= 0 -> 4;
   Value > -128 -> 1;
   Value > -32767 -> 2;
   Value > -2147483647 -> 4
end.

Is there a faster way (possibly bit manipulation?) to find the size needed for an integer of a given value? Here's what I've got:

uint_length(Value) ->
if Value < 256 -> 1;
   Value < 65535 -> 2;
   Value < 4294967295 -> 4
end.

sint_length(Value) ->
if Value < 128 andalso Value >= 0 -> 1;
   Value < 32767 andalso Value >= 0 -> 2;
   Value < 2147483647 andalso Value >= 0 -> 4;
   Value > -128 -> 1;
   Value > -32767 -> 2;
   Value > -2147483647 -> 4
end.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

埋情葬爱 2024-08-08 23:22:27

如前所述,表示以 2 为底的数字所需的位数可以使用对数来计算。 比如Erlang中的如下代码。

bits(0) -> 
  1;
bits(X) when is_number(X), X < 0 ->
  1 + bits(erlang:abs(X));
bits(X) when is_number(X) ->
  erlang:trunc(math:log(X) / math:log(2) + 1).

如果您只关心字长 1,2 和 4,那么最好只检查少数限制。 我喜欢使用 Erlang 的基数表示法以 16 为基数作为限制。

unsigned_wordsize(X) when is_integer(X), X >= 0 ->
  case X of
    _ when X =< 16#000000ff -> 1;
    _ when X =< 16#0000ffff -> 2;
    _ when X =< 16#ffffffff -> 4
  end.

我从你的代码中假设你正在使用二进制补码作为有符号整数。 因此,我将负数映射到正数,这样我就可以使用同一张表。

signed_wordsize(X) when is_integer(X), X < 0 ->
  signed_wordsize(-(X+1));
signed_wordsize(X) when is_integer(X) ->
  case X of
    _ when X =< 16#0000007f -> 1;
    _ when X =< 16#00007fff -> 2;
    _ when X =< 16#7fffffff -> 4
  end.

As mentioned, the number of bits needed to represent a number in base two can be calculated using logarithms. Such as the following code in Erlang.

bits(0) -> 
  1;
bits(X) when is_number(X), X < 0 ->
  1 + bits(erlang:abs(X));
bits(X) when is_number(X) ->
  erlang:trunc(math:log(X) / math:log(2) + 1).

If you are only concerned with word sizes 1,2 and 4, then it is of course nice to check only the few limits. I like to use base 16 for the limits using Erlang's radix notation.

unsigned_wordsize(X) when is_integer(X), X >= 0 ->
  case X of
    _ when X =< 16#000000ff -> 1;
    _ when X =< 16#0000ffff -> 2;
    _ when X =< 16#ffffffff -> 4
  end.

And I assume from your code that you are using two's complement for signed integers. So I map negative numbers over to positive so I can use the same table.

signed_wordsize(X) when is_integer(X), X < 0 ->
  signed_wordsize(-(X+1));
signed_wordsize(X) when is_integer(X) ->
  case X of
    _ when X =< 16#0000007f -> 1;
    _ when X =< 16#00007fff -> 2;
    _ when X =< 16#7fffffff -> 4
  end.
江城子 2024-08-08 23:22:27

取以 2 为底的对数,除以 8,然后向上舍入到最接近的无符号整数整数。 对于有符号,除了除以 8 之前的 + 1 之外相同。

如果您没有允许您指定底数的对数函数,您可以简单地通过以下方式转换底数:

log_base_2(value) = log(value)/log(2) # if you have log() for log-base10
log_base_2(value) = ln(value)/ln(2) # if you have ln() for log-base-e

示例计算:

To store 368:

ln(368) ~= 5.908
ln(368)/ln(2) ~= 8.524
( ln(368)/ln(2) ) / 8 ~= 1.065

Rounding up gives 1.065 -> 2, thus we need 2 bytes to store 368 as an unsigned integer.

这适用于任意大的数字。 如果您将自己限制为仅可能 1,2 或 4 字节结果,那么仅使用您拥有的切换逻辑可能是最快的方法。

Take the logarithm, base 2, divide it by 8, and round it up to the nearest whole number for unsigned ints. For signed, the same except + 1 before the division by 8.

If you don't have a logarithm function that allows you to specify the base, you can simply convert base via this instead:

log_base_2(value) = log(value)/log(2) # if you have log() for log-base10
log_base_2(value) = ln(value)/ln(2) # if you have ln() for log-base-e

Example calculation:

To store 368:

ln(368) ~= 5.908
ln(368)/ln(2) ~= 8.524
( ln(368)/ln(2) ) / 8 ~= 1.065

Rounding up gives 1.065 -> 2, thus we need 2 bytes to store 368 as an unsigned integer.

This is for arbitrarily large numbers. If you're limiting yourself to only potentially 1,2, or 4 byte results, then just using the switching logic you have is probably the fastest method.

独自←快乐 2024-08-08 23:22:27

对于您的 uint,它应该是 "<= 65535""<65536"。 232 也是如此,但第一个 (256) 还可以。

我会选择:

uint_length(Value) ->
if Value <=   255 -> 1;
   Value <= 65535 -> 2;
   true           -> 4
end.

sint_length(Value) ->
if Value <=   127 andalso Value >=   -128 -> 1;
   Value <= 32767 andalso Value >= -32768 -> 2;
   true                                   -> 4
end.

这假设您将参数限制为 32 位。 如果不是,请添加更多条件来限制更大的数字。 我认为您的原始代码无论如何都不会为他们工作,因为至少有一个条件应该评估为真。

For your uints, it should either be "<= 65535" or "< 65536". Ditto for 232 but the first one (256) is okay.

I would go for:

uint_length(Value) ->
if Value <=   255 -> 1;
   Value <= 65535 -> 2;
   true           -> 4
end.

sint_length(Value) ->
if Value <=   127 andalso Value >=   -128 -> 1;
   Value <= 32767 andalso Value >= -32768 -> 2;
   true                                   -> 4
end.

This assumes you'll be limiting arguments to 32 bits. If not, add more conditions to hamdle the larger numbers. I don't think your original code would have worked for them anyway since at least one condition is supposed to evaluate true.

套路撩心 2024-08-08 23:22:27

简单来说怎么样:

nr_bytes(Value) ->
  if Value < 256 -> 1;
     true        -> 1 + nr_bytes(Value bsr 8)
  end.

How about simply:

nr_bytes(Value) ->
  if Value < 256 -> 1;
     true        -> 1 + nr_bytes(Value bsr 8)
  end.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文