Обратите внимание, что проблема подсчета 1-бит называется «подсчет населения».
По крайней мере в Ruby, придерживайтесь обработки их как строки с помощью метода count
, если только у вас нет веских причин использовать целые числа.
count
Тест: 78,60 с для 10 000 000 итераций (127 225,63 итераций в секунду)
Для целых чисел,
Если вас не интересуют значения выше 2**32
,
def popcount(x)
m1 = 0x55555555
m2 = 0x33333333
m4 = 0x0f0f0f0f
x -= (x >> 1) & m1
x = (x & m2) + ((x >> 2) & m2)
x = (x + (x >> 4)) & m4
x += x >> 8
return (x + (x >> 16)) & 0x3f
end
Тест: 105,73 с для 10 000 000 итераций (94 579,03 итераций в секунду)
Если вам небезразличны значения выше 2**32
,
def popcount(x)
b = 0
while x > 0
x &= x - 1
b += 1
end
return b
end
Тест: 365,59 с для 10 000 000 итераций (27 353,27 итераций в секунду)
Addenda:
Ваш код:
Тест: 78,25 с для 1 000 000 итераций (12 779,56 итераций в секунду)
Этот код:
def bit_vec(str)
# alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
bv = "0" * 52
str.each_char do |c|
ord = c.ord
next unless (ord >= 65 && ord <= 90) || (ord >= 97 && ord <= 122)
index = ord - 65
index -= 6 if index > 25
bv[index] = "1"
break if bv == "1111111111111111111111111111111111111111111111111111"
end
bv
end
Примечание: Вы сказали, что имеете дело с 52-битным числом, поэтому я предположил, что вам небезразличны как прописные, так и строчные буквы (26 + 26 = 52). Сначала я решил проверить прописные буквы, потому что так они выглядят практически в каждом наборе символов, что немного упрощает вычисления.
Тест: 24,86 с для 1 000 000 итераций (40 231,60 итераций в секунду)
3,14x ускорение.