是否有更快的方法(可能是位操作?)来找到给定值的整数所需的大小?这就是我所拥有的:
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.
答案 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.