İmzasız bir on altı bit tamsayıdakilerin sayısını sayan bazı ifadeler yazın.
Girişidir Örneğin, 1337
ardından sonucudur 6
çünkü 1337
bir onaltı bitlik ikili sayı olarak 0000010100111001
altı olanları içeren,.
İmzasız bir on altı bit tamsayıdakilerin sayısını sayan bazı ifadeler yazın.
Girişidir Örneğin, 1337
ardından sonucudur 6
çünkü 1337
bir onaltı bitlik ikili sayı olarak 0000010100111001
altı olanları içeren,.
Yanıtlar:
F3 0F B8 C1
tamsayı alır cx
ve sayımı çıkarır ax
ve buna eşdeğerdir:
popcnt ax, cx ; F3 0F B8 C1
Ve burada bir olduğunu 11 10 POPCNT kullanmayan bayt çözümü:
31 C0 D1 E9 10 E0 85 C9 75 F8
hangi eşdeğerdir:
xor ax, ax ; 31 C0 Set ax to 0
shr cx, 1 ; D1 E9 Shift cx to the right by 1 (cx >> 1)
adc al, ah ; 10 E0 al += (ah = 0) + (cf = rightmost bit before shifting)
test cx, cx ; 85 C9 Check if cx == 0
jnz $-6 ; 75 F8 Jump up to shr cx, 1 if not
ax
ve cx
ile eax
ve ecx
32-bit değiştirir. Bayt kodu her ikisi için de aynıdır.
bin(s).count('1')
bin
Yerleşik getiri tamsayı ikili dizeye dönüştürülür. Daha sonra 1
rakamları sayarız :
>>> s=1337
>>> bin(s)
'0b10100111001'
>>> bin(s).count('1')
6
for(n=0;x;n++)x&=x-1;
"bazı ifadeler yaz" dedin ("işlev" değil), bu yüzden numaranın girildiğini ve 1'lerin sayısının x
geri döndüğünü varsaydım n
. Başlatmam gerekmiyorsa n
3 bayt kaydedebilirim.
Bu, bir ifadenin x&x-1
2 gücü olup olmadığını test etmek için ünlü ifadenin uyarlanmasıdır ( eğer yanlışsa, doğru değilse).
İşte soruya göre 1337 numara ile ilgili eylem var. 1 çıkarma işleminin en az önemli 1 bit ve tüm sıfırları sağa çevirdiğini unutmayın.
0000010100111001 & 0000010100111000 = 0000010100111000
0000010100111000 & 0000010100110111 = 0000010100110000
0000010100110000 & 0000010100101111 = 0000010100100000
0000010100100000 & 0000010100011111 = 0000010100000000
0000010100000000 & 0000010011111111 = 0000010000000000
0000010000000000 & 0000001111111111 = 0000000000000000
EDIT: bütünlüğü için, işte bir bayt daha uzun olan ve biraz daha yavaş olan saf algoritma.
for(n=0;x;x/=2)n+=x&1;
{}
. Bu kadar basit bir iş, birisinin çoktan gelmesine şaşırmamam gerekirdi.
for(n=0;x;x/=2)n+=x&1;
n->sum(digits(n,2))
Bu, tek bir argümanı kabul eden anonim bir işlev oluşturur n
,. Kullanmak için, f=n->...
onun gibi bir şeye atayın ve onun gibi söyleyin f(1337)
.
digits()
2 argüman çağrıldığında fonksiyonu, belirli bir baz girdi basamak dizisi döndürür. Bu yüzden digits(n, 2)
ikili rakamını döndürür n
. Dizinin toplamını alın ve ikili gösterimdeki sayıların sayısını elde edin n
.
count_ones
ri2b:+
ri "Read the input and convert it to integer";
2b "Convert the integer into base 2 format";
:+ "Sum the digits of base 2 form";
sum(intToBits(scan())>0)
scan()
stdin'den girdi okur.
intToBits()
bir tamsayı alır ve raw
sıfırı ve girişin ikili gösterimini içeren bir vektör türünü döndürür .
intToBits(scan())>0
Her elemanın TRUE
karşılık gelen ikili vektör elemanının 1 olduğu bir mantıksal vektör (aksi halde tüm elemanlar 0 ya da 1 ve 1> 0 olduğundan) döndürür FALSE
.
R'de, TRUE
elemanların sayısını almak için mantıksal bir vektör toplayabilirsiniz, bu nedenle mantıksal vektörleri yukarıdaki gibi toplamak bize ne istediğimizi alır.
Not sum()
işleyemez raw
doğrudan girişi, Mantıksal bölümler kullanılarak dolayısıyla geçici çözüm.
sum(intToBits(scan()))
Aynı olmaz mıydı ?
sum()
, o zaman türden girdi alamıyor raw
, ki geri döndüğü şey intToBits()
.
: c ?dup if dup 1- and recurse 1+ then ;
0 1337 c
Gerçek bir işleve ihtiyaç duyulursa, ikinci satır
: c 0 swap c ;
ve sen buna "1337 c" diyorsun. Forth'un nispeten ayrıntılı kontrol sözcükleri bunu zorlaştırıyor (aslında, bunlardan bir çoğunu zorlaştırıyorlar).
Düzenleme: Önceki sürümüm negatif sayıları doğru işlemiyordu.
Beni hatırlattığı için alephalpha'ya teşekkürler DigitCount
.
DigitCount[#,2,1]&
Bu, biraz daha kısaltılabilen basit bir özyinelemeli fonksiyondur. Sadece biraz zaman alıyor ve tekrar çalışıyor:
B=n=>n&&(1&n)+B(n>>1)
Bunu http://www.es6fiddle.net/imt5ilve/ adresinde deneyin ( var
sebebi 'use strict';
).
Balık yendiğime inanamıyorum !!!
Eski olan:
n=>n.toString(2).split(1).length-1
Her iki fonksiyon da kolayca ES5'e uyarlanabilir:
function B(n){return n?(1&n)+B(n>>1):0}
//ungolfed:
function B(number)
{
if( number > 0 )
{
//arguments.callee points to the function itself
return (number & 1) + arguments.callee( number >> 1 );
}
else
{
return 0;
}
}
Eski olan:
function(n){return n.toString(2).split(1).length-1}
@ user1455003 bana en küçüğü tetikleyen harika bir fikir verdi:
function B(n,x){for(x=0;n;n>>=1)x+=n&1;return x}
ES6'ya uyarladım ve çok kısaltmak için özyinelemeye yaptım!
0$11.>~n;
2,:?!^:2%:{+}-
Program sadece tekrarlanan mod 2'yi yapar, giriş numarası sıfır olana kadar çıkarır ve böler, ardından mod 2'lerin toplamını yazdırır.
-v
Bayrakla test edin , örneğin
py -3 fish.py ones.fish -v 1337
-v
Bayrak versiyonu hala çalışıyor.)
Bu benim ES6 cevabım ile aynı yaklaşımı kullanır
<?=count(split(1,decbin($_GET[n])))-1;
Bu tam bir koddur, yalnızca bir dosyaya koymanız ve tarayıcıyla erişmeniz yeterlidir n=<number>
.
Bu biraz daha kısa:
<?=count(split(1,decbin($n)))-1;
Direktifi, çünkü bu sadece PHP <4.2 üzerinde güvenilir bir şekilde çalışır register_globals
olarak ayarlandı Off
(o sırada çıkarıldı) PHP5.4 için PHP4.2 kadar varsayılan olarak.
php.ini
Ile bir dosya oluşturursanız register_globals=On
, bu işe yarayacak.
Kodu kullanmak için, POST veya GET ile bir tarayıcı kullanarak dosyaya erişin.
Fonksiyonu çok ilginç bir şekilde kullanan 2 çok iyi öneride bulundu array_sum
:
38 bayt:
<?=array_sum(str_split(decbin(1337)));
45 bayt:
<?=array_sum(preg_split('//', decbin(1337)));
Bu gerçekten harika bir fikir ve biraz daha kısaltılabilir, 36 byte uzunluğunda olabilir:
<?=array_sum(split(1,decbin(1337)));
<?=substr_count(decbin(1337),"1");
(34 bayt) kullanarak dört bayt kazanın
<?=substr_count(decbin(1337),1);
. Bu toplam 32 bayttır. Yeterince farklı bir kod olduğu düşünüldüğünde, bunu kendi cevabınız olarak göndermek istemez misiniz? Ben surelly buna oy verecek!
<?=substr_count(decbin($argv[1]),1);
(veya $_GET[n]
; 36 bayt)
¢o1 l
de işe yarayacaktı. Diğer ilginç bir yaklaşım ise -¢¬r-0
; ¢¬
İkili basamak dizisine ayrılır, r-0
çıkartma ile azalır, 0'dan başlar ve -
sonucu olumsuzlar.
¢¬x
.
Rekabet etmeyen cevap. Balmumu bu mücadeleden daha yeni.
Bu çözüm Brian Kherigan'ın “Bit Twiddling Hacks” web sitesinden set bit sayma yöntemini kullanıyor.
Sadece yineleme sırasında, bit sayısını artırarak bir döngü geçiyor number=number&(number-1)
kadarnumber = 0
. Çözüm, yalnızca ayarlanan bitlerin olduğu kadar sık döngüden geçer.
Birkaç byte yeniden düzenleyerek 4 byte tıraş olabilir. Hem kaynak kodu hem de açıklama güncellendi:
pT_
>"p~0+M~p
d~0~@P@&<
{@<
Açıklama:
pT_ generate IP, input Integer, redirect
>" if top lstack value > 0 jump next instruction,
otherwise continue at next instruction
p redirect if top lstack value=0 (see below)
~ flip top and 2nd lstack values
0+ set top lstack value to 0, set top=top+2nd
M decrement top lstack value
~ flip top and 2nd lstack values
p redirect to lower left
< redirect to left
& top=top&2nd
@ flip top and 3rd lstack values
@P increment top lstack value, flip top and 3rd values
~0~ flip top and 2nd values, set top=0, flip top and 2nd again
d redirect to upper left
>"p~0+M..... loop back
p if top lstack = 0 at " instruction (see above), redirect
0 set lstack top to zero (irrelevant instruction)
< redirect to the left
@ flip top and 3rd lstack values
{ output top lstack value as integer (bitcount)
Klon benim GitHub depo balmumu tercüman, dil spesifikasyonları ile örnekler içeren.
İçin çalışır byte
, short
, char
, ve int
. Bir lambda olarak kullanın.
Integer::bitCount
Yerleşik kullanmadan:
42 bayt
s->{int c=0;for(;s!=0;c++)s&=s-1;return c}
sum(dec2bin(s)-48)
Örnek:
octave:1> s=1337
s = 1337
octave:2> sum(dec2bin(s)-48)
ans = 6
"$([char[]][convert]::ToString($s,2)|%{"+$_"})"|iex
Açıklama:
[convert]::ToString($s,2)
dan bir ikili dize temsili üretiyor $s
.
[char[]]
char dizisi olarak yazar ve her karakterin numaralandırılmasını sağlar.
|%{"+$_"}
her bir karakteri bir + işaretiyle
"$()"
dolaylı .ToString()
olarak ortaya çıkan alt ifadeye çağırarak
|iex
hazırlar, dizilenmiş dizgenin toplamını (yani.
-join
operatörü ve .ToString()
45 [char[]][convert]::ToString($s,2)-join'+'|iex
-replace
([convert]::ToString($s,2)-replace0).length
#(count(filter #{\1}(Long/toString % 2)))
Sağdan sola okuma, ikili bir dizgeye dönüştürme, bir karakter dizisine dönüştürme, 1
s'de filtreleme ve kaç tane kullandığınızı sayma.
EDİTMELİ Sieg'in yardımıyla
#(count(filter #{\1}(Integer/toString% 2)))
#(count(filter #{\1}(Integer/toString % 2)))
CompilerException java.lang.IllegalArgumentException: No matching method: toString_PERCENT_
Integer/toString
. Yine de bir saniye önce çalıştı.
t 0=[]
t n=t(quot n 2)++[rem n 2]
f=sum.t
fonksiyon beyan f :: Integer -> Integer
gibi etkileşimli yorumlayıcıdan kullanımını f <number>
veya satır ekleyin main=print$f <number>
Dosyanın sonuna.
rem n 2
s yerine onun bir listesini oluşturmaya ve kullanarak div
yerine quot
: t 0=0
t n=t(div n 2)+rem n 2
hayır - f
Artık değil.
⨭⟦ïⓑ
Girdiyi ikiliye dönüştürür, karakter sayısı boyunca böler ve elde edilen dizinin toplamını alır.