更快/更简洁的方法来确定存储签名/未签名的整数所需的正确大小?

时间:2009-08-11 03:26:22

标签: erlang

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

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.

4 个答案:

答案 0 :(得分:3)

如上所述,表示基数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,那么只检查几个限制当然很好。我喜欢使用基数16作为使用Erlang的基数表示法的限制。

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.

答案 1 :(得分:1)

取对数,基数2,除以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字节结果,那么只使用你所拥有的开关逻辑可能是最快的方法。

答案 2 :(得分:1)

对于您的提示,它应该是"<= 65535""< 65536"。同上2 32 但第一个(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位。如果没有,请添加更多条件以圈选较大的数字。我认为你的原始代码无论如何都不适合他们,因为至少有一个条件应该评估为真。

答案 3 :(得分:0)

简单地说:

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