Счетчик битов или вес Хемминга строки битов в эликсире?

Пожалуйста, как мы можем efficiently рассчитать вес Хемминга для струн в эликсире?

Пример: 0b0101101001 имеет вес Хэмминга 5 (т.е. набор 5 битов)

Моя попытка:

iex> Enum.count(Integer.to_char_list(n,2),&(&1===49)) 

2 ответа

Решение

Вот более эффективное решение, которое (для меня) также показывает намерение более четко:

for(<<bit::1 <- :binary.encode_unsigned(n)>>, do: bit) |> Enum.sum

Бенчмарк с использованием 100.000 двоичных цифр:

Benchfella.start

defmodule HammingBench do
  use Benchfella

  @n Stream.repeatedly(fn -> Enum.random [0, 1] end)
    |> Enum.take(100_000)
    |> Enum.join
    |> String.to_integer(2)

  bench "CharlesO" do
    Enum.count(Integer.to_char_list(@n,2),&(&1===49)) 
  end

  bench "Patrick Oscity" do
    for(<<bit::1 <- :binary.encode_unsigned(@n)>>, do: bit) |> Enum.sum
  end
end

Результаты тестов:

$ mix bench
Compiled lib/hamming_bench.ex
Generated hamming_bench app
Settings:
  duration:      1.0 s

## HammingBench
[20:12:03] 1/2: Patrick Oscity
[20:12:06] 2/2: CharlesO

Finished in 8.4 seconds

## HammingBench
Patrick Oscity         500   4325.79 µs/op
CharlesO                 1   5754094.00 µs/op

Хотя ответ Патрика верен для положительных целых чисел, он не будет работать для отрицательных чисел, поскольку:binary.encode_unsigned/1не справляется с ними.

Использовать

Вместо этого я бы предложил использовать мощный Эликсир.<<>>оператор битовой строки (который также выглядит лучше IMO):

      Enum.sum(for << bit::1 <- <<n>> >>, do: bit))

Вы также можете указать целочисленный размер как 16-битный, 32-битный или любой другой:

      <<n::integer-32>>

Подсчет битов за один проход

В качестве альтернативного подхода вы также можете подсчитывать биты напрямую за один раз вместо того, чтобы сначала извлекать все биты, а затем суммировать их:

      defmodule HammingWeight do
  def weight(int) when is_integer(int) do
    w(<<int>>, 0)
  end

  defp w(<<>>>, count),                do: count
  defp w(<<0::1, rest::bits>>, count), do: w(rest, count)
  defp w(<<1::1, rest::bits>>, count), do: w(rest, count + 1)
end

Другие вопросы по тегам