سؤال

نظرا MATLAB uint32 أن تفسر على أنها سلسلة بت, ما هو فعال وموجزة طريقة إحصاء عدد غير صفرية بت في السلسلة ؟

لدي العامل ، من السذاجة نهج الحلقات على البتات ، لكنها بطيئة جدا لاحتياجاتي.(تنفيذ C++ باستخدام std::bitset عدد() يعمل على الفور تقريبا).

لقد وجدت جميلة جدا صفحة سرد مختلف قليلا تقنيات العد, ولكن أنا على أمل هناك سهلة MATLAB سقو.

http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetNaive


تحديث #1

فقط نفذ براين كيرنيغان الخوارزمية على النحو التالي:

w = 0;
while ( bits > 0 )
    bits = bitand( bits, bits-1 );
    w = w + 1;
end

الأداء لا يزال كربي, أكثر من 10 ثوان إلى حساب فقط 4096^2 حسابات الوزن.بلدي رمز C++ باستخدام عدد() من الأمراض المنقولة جنسيا::bitset هل هذا في subsecond الوقت.


تحديث #2

هنا هو جدول تشغيل مرات تقنيات لقد حاولت حتى الآن.وسوف أقوم بتحديث هذا الموضوع وأنا على أفكار إضافية/اقتراحات.

Vectorized Scheiner algorithm                =>    2.243511 sec
Vectorized Naive bitget loop                 =>    7.553345 sec
Kernighan algorithm                          =>   17.154692 sec
length( find( bitget( val, 1:32 ) ) )        =>   67.368278 sec
nnz( bitget( val, 1:32 ) )                   =>  349.620259 sec
Justin Scheiner's algorithm, unrolled loops  =>  370.846031 sec
Justin Scheiner's algorithm                  =>  398.786320 sec
Naive bitget loop                            =>  456.016731 sec
sum(dec2bin(val) == '1')                     => 1069.851993 sec


التعليق:على dec2bin() وظيفة في مطلب يبدو ضعيفا جدا تنفيذها.تشغيله بطيئة للغاية.

التعليق:"من السذاجة bitget حلقة" خوارزمية تنفذ على النحو التالي:

w=0;
for i=1:32
   if bitget( val, i ) == 1
       w = w + 1;
   end
end

التعليق:حلقة بسطه نسخة من Scheiner خوارزمية يبدو كما يلي:

function w=computeWeight( val )
w = val;
w = bitand(bitshift(w, -1), uint32(1431655765)) + ...
    bitand(w, uint32(1431655765));

w = bitand(bitshift(w, -2), uint32(858993459)) + ...
    bitand(w, uint32(858993459));

w = bitand(bitshift(w, -4), uint32(252645135)) + ...
    bitand(w, uint32(252645135));

w = bitand(bitshift(w, -8), uint32(16711935)) + ...
    bitand(w, uint32(16711935));

w = bitand(bitshift(w, -16), uint32(65535)) + ...
    bitand(w, uint32(65535));
هل كانت مفيدة؟

المحلول

سأكون مهتما لمعرفة مدى سرعة هذا الحل هو:

function r = count_bits(n)

shifts = [-1, -2, -4, -8, -16];
masks = [1431655765, 858993459, 252645135, 16711935, 65535];

r = n;
for i=1:5
   r = bitand(bitshift(r, shifts(i)), masks(i)) + ...
      bitand(r, masks(i));
end

العودة, أرى أن هذا هو "موازية" حل معين على bithacks الصفحة.

نصائح أخرى

إلا إذا كان هذا هو مطلب تنفيذ العملية ، قد تريد أن تأخذ فقط الخاص بك سريع C++ تنفيذ وتجميع أنها mex وظيفة ، مرة واحدة في النظام الأساسي الهدف.

تحرير:حل جديد

ويبدو أن كنت ترغب في تكرار حساب لكل عنصر في 4096-من قبل-4096 مجموعة من UINT32 القيم.إذا كان هذا هو ما تقوم به, أعتقد أن أسرع طريقة للقيام بذلك في MATLAB هو استخدام حقيقة أن BITGET هي مصممة للعمل على المصفوفات من القيم.رمز تبدو مثل هذا:

numArray = ...your 4096-by-4096 matrix of uint32 values...
w = zeros(4096,4096,'uint32');
for iBit = 1:32,
  w = w+bitget(numArray,iBit);
end

إذا كنت تريد أن تجعل vectorized إصدارات بعض خوارزميات أخرى ، وأعتقد الدالة bitand هو أيضا مصمم للعمل على المصفوفات.


الحل القديم...

أسهل طريقة يمكنني التفكير به هو استخدام DEC2BIN وظيفة يعطيك تمثيل ثنائي (كسلسلة) من عدد صحيح غير سالب:

w = sum(dec2bin(num) == '1');  % Sums up the ones in the string

انها بطيئة, ولكن من السهل.=)

نفذت "أفضل 32 بت خوارزمية" من جامعة ستانفورد الرابط في الأعلى.تحسين خوارزمية تخفيض وقت المعالجة بنسبة 6%.الأمثل أيضا حجم قطعة وجدت أن 32K مستقرة ويحسن الوقت بنسبة 15% على 4K.نتوقع 4Kx4K الوقت إلى أن 40% من Vectorized Scheiner الخوارزمية.

function w = Ham(w)
% Input uint32
% Output vector of Ham wts
 for i=1:32768:length(w)
  w(i:i+32767)=Ham_seg(w(i:i+32767));
 end
end

% Segmentation gave reduced time by 50%

function w=Ham_seg(w)
 %speed
 b1=uint32(1431655765); 
 b2=uint32(858993459);
 b3=uint32(252645135);
 b7=uint32(63); % working orig binary mask

 w = bitand(bitshift(w, -1), b1) + bitand(w, b1);
 w = bitand(bitshift(w, -2), b2) + bitand(w, b2);
 w =bitand(w+bitshift(w, -4),b3);
 w =bitand(bitshift(w,-24)+bitshift(w,-16)+bitshift(w,-8)+w,b7);

end

هل توقيت بعض المقارنات على Matlab كودي.تحديد مجزأة تعديل Vectorized Scheiner يعطي optimimum الأداء.

لديك >50% تخفيض الوقت على أساس كودي 1.30 ثانية إلى 0.60 ثانية تغيير L=4096*4096 ناقلات.

function w = Ham(w)
% Input uint32
% Output vector of Ham wts

 b1=uint32(1431655765); % evaluating saves 15% of time 1.30 to 1.1 sec
 b2=uint32(858993459);
 b3=uint32(252645135);
 b4=uint32(16711935);
 b5=uint32(65535);

 for i=1:4096:length(w)
  w(i:i+4095)=Ham_seg(w(i:i+4095),b1,b2,b3,b4,b5);
 end
end

% Segmentation reduced time by 50%

function w=Ham_seg(w,b1,b2,b3,b4,b5)
 % Passing variables or could evaluate b1:b5 here


 w = bitand(bitshift(w, -1), b1) + bitand(w, b1);
 w = bitand(bitshift(w, -2), b2) + bitand(w, b2);
 w = bitand(bitshift(w, -4), b3) + bitand(w, b3);
 w = bitand(bitshift(w, -8), b4) + bitand(w, b4);
 w = bitand(bitshift(w, -16), b5) + bitand(w, b5);

end





vt=randi(2^32,[4096*4096,1])-1;
% for vt being uint32 the floor function gives unexpected values
tic
v=num_ones(mod(vt,65536)+1)+num_ones(floor(vt/65536)+1); % 0.85 sec
toc
% a corrected method is
v=num_ones(mod(vt,65536)+1)+num_ones(floor(double(vt)/65536)+1);
toc

سريع النهج عد بت في كل بايت باستخدام جدول البحث ، ثم تلخيص هذه القيم ؛ في الواقع, انها واحدة من النهج المقترح على صفحة ويب معينة في السؤال.الشيء الجميل في هذا النهج هو أن كل بحث و المبلغ vectorizable العمليات في MATLAB ، حتى تتمكن من vectorize هذا النهج وحساب المبالغة الوزن / عدد تعيين بت من عدد كبير من بت سلاسل في آن واحد ، بسرعة جدا.هذا النهج هو الذي نفذ في bitcount التقديم على MATLAB تبادل الملفات.

حاول تقسيم العمل إلى أجزاء أصغر.تخميني هو أنه إذا كنت تريد أن عملية جميع البيانات دفعة واحدة ، matlab تحاول أن تفعل كل عملية على جميع الأعداد الصحيحة قبل اتخاذ الخطوات المتعاقبة و المعالج ذاكرة التخزين المؤقت يبطل مع كل خطوة.

for i=1:4096,
    «process bits(i,:)»
end

أنا إحياء قديم الموضوع هنا لكن انا صادفت هذه المشكلة و لقد كتبت هذا قليلا من التعليمات البرمجية لذلك:

distance = sum(bitget(bits, 1:32));

تبدو جميلة موجزة ، ولكن أنا خائفة أن bitget يتم تنفيذها في O(n) bitshift عمليات.الكود يعمل ما أنا ذاهب ولكن مشكلتي مجموعة لا تعتمد على المبالغة الوزن.

num_ones=uint8(zeros(intmax('uint32')/2^6,1));
% one time load of array not implemented here
tic
for i=1:4096*4096
 %v=num_ones(rem(i,64)+1)+num_ones(floor(i/64)+1); % 1.24 sec
 v=num_ones(mod(i,64)+1)+num_ones(floor(i/64)+1); % 1.20 sec
end
toc
tic
num_ones=uint8(zeros(65536,1));
for i=0:65535
 num_ones(i+1)=length( find( bitget( i, 1:32 ) ) ) ;
end
toc
% 0.43 sec to load
% smaller array to initialize
% one time load of array
tic
for i=1:4096*4096
 v=num_ones(mod(i,65536)+1)+num_ones(floor(i/65536)+1); %  0.95 sec
 %v=num_ones(mod(i,65536)+1)+num_ones(bitshift(i,-16)+1); % 16 sec for 4K*1K
end
toc
%vectorized
tic
num_ones=uint8(zeros(65536,1));
for i=0:65535
 num_ones(i+1)=length( find( bitget( i, 1:32 ) ) ) ;
end % 0.43 sec
toc
vt=randi(2^32,[4096*4096,1])-1;
tic
v=num_ones(mod(vt,65536)+1)+num_ones(floor(vt/65536)+1); % 0.85 sec
toc
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top