A faster / more concise way to determine the correct size needed to store signed / unsigned ints?

Is there a faster way (maybe bit manipulation?) To find the size needed for an integer of a given value? Here is what I have:

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.
+3
source share
4 answers

As already mentioned, the number of bits required to represent two numbers in the base can be calculated using logarithms. For example, 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 interested in words of sizes 1,2 and 4, then, of course, it’s nice to check only a few restrictions. I like to use base 16 for limits using the Rhlar Erlang 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.

, . , .

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.
+3

, 2, 8 . , , + 1 8.

, , :

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 , , , , , .

+1

uint "<= 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.

This assumes that you are limiting the arguments to 32 bits. If not, add more conditions to iterate over large numbers. I don't think your source code would work for them anyway, since at least one condition must evaluate to true.

+1
source

How about just:

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

Source: https://habr.com/ru/post/1714835/


All Articles