Viết một số câu lệnh sẽ đếm số lượng câu lệnh trong một số nguyên mười sáu bit không dấu.
Ví dụ, nếu đầu vào là 1337
, thì kết quả là 6
bởi vì 1337
số nhị phân mười sáu bit là 0000010100111001
, chứa sáu số.
Viết một số câu lệnh sẽ đếm số lượng câu lệnh trong một số nguyên mười sáu bit không dấu.
Ví dụ, nếu đầu vào là 1337
, thì kết quả là 6
bởi vì 1337
số nhị phân mười sáu bit là 0000010100111001
, chứa sáu số.
Câu trả lời:
F3 0F B8 C1
trong đó lấy số nguyên trong cx
và xuất ra số đếm ax
và tương đương với:
popcnt ax, cx ; F3 0F B8 C1
Và đây là một giải pháp 11 10 byte không sử dụng POPCNT:
31 C0 D1 E9 10 E0 85 C9 75 F8
tương đương với:
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
và cx
bằng eax
và ecx
thay đổi nó thành 32 bit. Mã byte là giống nhau cho một trong hai.
bin(s).count('1')
Các bin
built-in trả về số nguyên chuyển thành một chuỗi nhị phân. Sau đó chúng tôi đếm các 1
chữ số:
>>> s=1337
>>> bin(s)
'0b10100111001'
>>> bin(s).count('1')
6
for(n=0;x;n++)x&=x-1;
bạn đã nói "viết một số câu lệnh" (không phải "một hàm") vì vậy tôi đã giả sử số được cung cấp x
và số 1 được trả về n
. Nếu tôi không phải khởi tạo, n
tôi có thể tiết kiệm 3 byte.
Đây là bản chuyển thể của biểu thức nổi tiếng x&x-1
để kiểm tra nếu thứ gì đó có sức mạnh bằng 2 (sai nếu đúng, đúng nếu không.)
Đây là hành động trên số 1337 từ câu hỏi. Lưu ý rằng trừ đi 1 lần lật ít nhất 1 bit và tất cả các số 0 ở bên phải.
0000010100111001 & 0000010100111000 = 0000010100111000
0000010100111000 & 0000010100110111 = 0000010100110000
0000010100110000 & 0000010100101111 = 0000010100100000
0000010100100000 & 0000010100011111 = 0000010100000000
0000010100000000 & 0000010011111111 = 0000010000000000
0000010000000000 & 0000001111111111 = 0000000000000000
EDIT: để hoàn thiện, đây là thuật toán ngây thơ, dài hơn một byte (và chậm hơn một chút.)
for(n=0;x;x/=2)n+=x&1;
{}
. Đó là một nhiệm vụ đơn giản như vậy tôi không nên ngạc nhiên khi ai đó đã nghĩ ra nó.
for(n=0;x;x/=2)n+=x&1;
n->sum(digits(n,2))
Điều này tạo ra một hàm ẩn danh chấp nhận một đối số duy nhất , n
. Để sử dụng nó, gán nó cho một cái gì đó như f=n->...
và gọi nó như thế nào f(1337)
.
Các digits()
chức năng, khi được gọi với 2 đối số, trả về một mảng của các chữ số của đầu vào trong cơ sở nhất định. Vì vậy, digits(n, 2)
trả về các chữ số nhị phân của n
. Lấy tổng của mảng và bạn có số lượng trong biểu diễn nhị phân của 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()
đọc đầu vào từ stdin.
intToBits()
lấy một số nguyên và trả về một vectơ loại raw
chứa các số 0 và một số của biểu diễn nhị phân của đầu vào.
intToBits(scan())>0
trả về một vectơ logic trong đó mỗi phần tử là TRUE
nếu phần tử vectơ nhị phân tương ứng là 1 (vì tất cả các phần tử là 0 hoặc 1 và 1> 0), nếu không FALSE
.
Trong R, bạn có thể tổng hợp một vectơ logic để có được số lượng TRUE
phần tử, do đó, việc tổng hợp vectơ logic như trên sẽ cho chúng ta những gì chúng ta muốn.
Lưu ý rằng sum()
không thể xử lý raw
đầu vào trực tiếp, do đó cách giải quyết bằng cách sử dụng logic.
sum(intToBits(scan()))
giống nhau?
sum()
không thể lấy đầu vào của loại raw
, đó là những gì được trả về intToBits()
.
: c ?dup if dup 1- and recurse 1+ then ;
0 1337 c
Nếu một chức năng thực sự là cần thiết thì dòng thứ hai trở thành
: c 0 swap c ;
và bạn gọi nó bằng "1337 c". Các từ kiểm soát tương đối dài dòng của Forth làm cho điều này trở nên khó khăn (thực ra, chúng tạo ra rất nhiều từ khó khăn này).
Chỉnh sửa: Phiên bản trước của tôi không xử lý chính xác các số âm.
Cảm ơn alephalpha đã nhắc nhở tôi DigitCount
.
DigitCount[#,2,1]&
Đây là một hàm đệ quy đơn giản có thể rút ngắn thêm một chút. Nó chỉ đơn giản là mất một chút và tự chạy lại:
B=n=>n&&(1&n)+B(n>>1)
Hãy thử nó trên http://www.es6fiddle.net/imt5ilve/ (bạn cần var
vì 'use strict';
).
Tôi không thể tin rằng tôi đã đánh cá !!!
Cái cũ:
n=>n.toString(2).split(1).length-1
Cả hai chức năng có thể dễ dàng thích ứng với ES5:
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;
}
}
Người già:
function(n){return n.toString(2).split(1).length-1}
@ user1455003 đã cho tôi một ý tưởng thực sự tuyệt vời, đó là 'kích hoạt' ý tưởng nhỏ nhất:
function B(n,x){for(x=0;n;n>>=1)x+=n&1;return x}
Tôi đã điều chỉnh nó thành ES6 và làm cho nó đệ quy để rút ngắn rất nhiều!
0$11.>~n;
2,:?!^:2%:{+}-
Chương trình chỉ thực hiện lặp lại mod 2, trừ và chia cho đến khi số đầu vào bằng 0, sau đó in tổng của mod 2s.
Kiểm tra với -v
cờ, ví dụ
py -3 fish.py ones.fish -v 1337
-v
Phiên bản cờ vẫn hoạt động.)
Điều này sử dụng cùng một aproach như câu trả lời ES6 của tôi
<?=count(split(1,decbin($_GET[n])))-1;
Đây là một mã đầy đủ, bạn chỉ cần đặt nó vào một tệp và truy cập nó trên trình duyệt, với tham số n=<number>
.
Cái này ngắn hơn một chút:
<?=count(split(1,decbin($n)))-1;
Điều này chỉ hoạt động đáng tin cậy trên PHP <4.2 vì lệnh register_globals
được đặt thànhOff
mặc định từ PHP4.2 lên đến PHP5.4 (đã bị xóa sau đó).
Nếu bạn tạo một php.ini
tập tin với register_globals=On
, điều này sẽ làm việc.
Để sử dụng mã, truy cập tệp bằng trình duyệt, bằng POST hoặc GET.
Ông đã đưa ra 2 gợi ý thực sự tốt có chức năng sử dụng rất thú vị array_sum
:
38 byte:
<?=array_sum(str_split(decbin(1337)));
45 byte:
<?=array_sum(preg_split('//', decbin(1337)));
Đây là một ý tưởng thực sự tuyệt vời và có thể rút ngắn thêm một chút, dài 36 byte:
<?=array_sum(split(1,decbin(1337)));
<?=substr_count(decbin(1337),"1");
(34 byte)
<?=substr_count(decbin(1337),1);
. Đó là tổng cộng 32 byte. Xem xét rằng đó là một mã đủ khác, bạn không muốn đăng nó dưới dạng câu trả lời của riêng mình? Tôi surelly sẽ upvote nó!
<?=substr_count(decbin($argv[1]),1);
(hoặc $_GET[n]
; 36 byte)
¢o1 l
cũng sẽ hoạt động tốt. Một cách tiếp cận thú vị khác là -¢¬r-0
; ¢¬
chia thành mảng các chữ số nhị phân, r-0
giảm bằng phép trừ, bắt đầu từ 0 và -
phủ định kết quả, làm cho nó dương.
¢¬x
.
Câu trả lời không cạnh tranh. Sáp ong mới hơn thử thách này.
Giải pháp này sử dụng cách đếm các bit set của Brian Kherigan từ trang web của Bit Bit Twiddling Hacks.
nó chỉ chạy qua một vòng lặp, tăng số bit, trong khi lặp qua number=number&(number-1)
cho đến khi number = 0
. Giải pháp chỉ đi qua vòng lặp thường xuyên như có các bit được đặt.
Tôi có thể tắt 4 byte bằng cách sắp xếp lại một vài hướng dẫn. Cả mã nguồn và giải thích đã được cập nhật:
pT_
>"p~0+M~p
d~0~@P@&<
{@<
Giải trình:
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)
Sao chép kho GitHub của tôi có chứa trình thông dịch sáp ong, thông số ngôn ngữ và ví dụ.
Làm việc cho byte
, short
, char
, và int
. Sử dụng như một lambda.
Integer::bitCount
Không sử dụng tích hợp:
42 byte
s->{int c=0;for(;s!=0;c++)s&=s-1;return c}
sum(dec2bin(s)-48)
Thí dụ:
octave:1> s=1337
s = 1337
octave:2> sum(dec2bin(s)-48)
ans = 6
Convert.ToString(X,2).Count(C=>C=='1');
"$([char[]][convert]::ToString($s,2)|%{"+$_"})"|iex
Giải thích:
[convert]::ToString($s,2)
tạo ra một đại diện chuỗi nhị phân từ $s
.
[char[]]
biến nó thành một mảng char và cho phép chúng ta liệt kê từng char.
|%{"+$_"}
chuẩn bị cho mỗi ký tự bằng dấu +
"$()"
gọi ngầm .ToString()
vào biểu thức con kết quả tính
|iex
tổng chuỗi (ví dụ: "+1 +0 +1 +1 +0 +1 +0 +0" = 4)
-join
toán tử nội tuyến và ẩn .ToString()
để đạt được 45 byte với [char[]][convert]::ToString($s,2)-join'+'|iex
... HOẶC, như một cách tiếp cận khác sử dụng -replace
toán tử nội tuyến để đạt được 43 byte với([convert]::ToString($s,2)-replace0).length
#(count(filter #{\1}(Long/toString % 2)))
Đọc từ phải sang trái, chuyển đổi thành chuỗi nhị phân, chuyển đổi thành một chuỗi các ký tự, lọc trên 1
s và đếm số lượng bạn có.
EDITED với sự giúp đỡ từ Sieg
#(count(filter #{\1}(Integer/toString% 2)))
#(count(filter #{\1}(Integer/toString % 2)))
CompilerException java.lang.IllegalArgumentException: No matching method: toString_PERCENT_
Integer/toString
. Nó đã làm việc một giây trước mặc dù.
t 0=[]
t n=t(quot n 2)++[rem n 2]
f=sum.t
khai báo hàm f :: Integer -> Integer
sử dụng từ trình thông dịch tương tác dưới dạng f <number>
hoặc thêm dòng main=print$f <number>
vào cuối tệp.
rem n 2
s thay vì xây dựng danh sách của nó và bằng cách sử dụng div
thay vì quot
: t 0=0
t n=t(div n 2)+rem n 2
- không f
còn nữa.
⨭⟦ïⓑ
Chuyển đổi đầu vào thành nhị phân, phân chia dọc theo ký tự và lấy tổng của mảng kết quả.