เลขฐานสองหนักไหม?


58

จำนวนเต็มเป็นเลขฐานสองถ้าการแทนค่าแบบไบนารีมีจำนวน1มากกว่า0s ขณะที่ละเว้นเลขศูนย์นำหน้า ตัวอย่างที่ 1 คือไบนารีหนักเป็นตัวแทนไบนารีเป็นเพียง1แต่ 4 100ไม่หนักไบนารีเป็นตัวแทนไบนารีของมันคือ ในกรณีที่มีการเสมอกัน (ตัวอย่างที่ 2 โดยมีการแทนค่าแบบไบนารี่10) จำนวนจะไม่ถือว่าเป็นเลขฐานสอง

กำหนดจำนวนเต็มบวกเป็นอินพุตให้ส่งออกค่าจริงหากเป็นเลขฐานสองหนักและค่าเท็จหากไม่ได้รับ

Testcases

รูปแบบ: input -> binary -> output

1          ->                                1 -> True
2          ->                               10 -> False
4          ->                              100 -> False
5          ->                              101 -> True
60         ->                           111100 -> True
316        ->                        100111100 -> True
632        ->                       1001111000 -> False
2147483647 ->  1111111111111111111111111111111 -> True
2147483648 -> 10000000000000000000000000000000 -> False

เกณฑ์การให้คะแนน

นี่คือจำนวนน้อยที่สุดในแต่ละภาษาที่ชนะ


จะเป็นอย่างไรถ้าภาษาของฉันไม่สามารถจัดการกับกรณีทดสอบล่าสุดได้เพราะมันอยู่นอกขอบเขตของสิ่งที่ถือว่าเป็นจำนวนเต็มบวก
musicman523

1
@ musicman523 afaik กฎ I / O มาตรฐานระบุว่าคุณจะต้องยอมรับตัวเลขที่สามารถแทนด้วยรูปแบบตัวเลขในภาษาของคุณ โปรดทราบว่า "การเล่นเกม" โดยใช้บางอย่างเช่น boolfuck ถือเป็นช่องโหว่มาตรฐาน
Skidsdev

ค่าความจริง / เท็จใด ๆ นับหรือเราต้องการสองค่าที่แตกต่างกันหรือไม่?
Erik the Outgolfer

@EriktheOutgolfer ค่าใด ๆ
Skidsdev

6
Aka A072600ถ้ามันช่วยใครก็ได้
dcsohl

คำตอบ:


28

x86 รหัสเครื่อง, 15 14 ไบต์

F3 0F B8 C1 0F BD D1 03 C0 42 2B D0 D6 C3

นี่คือฟังก์ชั่นที่ใช้ __fastcall แบบแผนการเรียกของ Microsoft (พารามิเตอร์ตัวแรกและตัวเดียวใน ecx, ค่าส่งคืนใน eax, callee ได้รับอนุญาตให้ปิดบัง edx) แม้ว่าจะสามารถแก้ไขเล็กน้อยสำหรับอนุสัญญาการโทรอื่น ๆ ที่ผ่านการขัดแย้งในการลงทะเบียน

มันจะกลับ 255 เป็นความจริงและ 0 เป็นเท็จ

จะใช้ที่ไม่มีเอกสาร ( แต่การสนับสนุนอย่างกว้างขวาง) salcopcode

ถอดชิ้นส่วนด้านล่าง:

;F3 0F B8 C1 
  popcnt eax, ecx ; Sets eax to number of bits set in ecx

;0F BD D1
  bsr edx, ecx    ; Sets edx to the index of the leading 1 bit of ecx

;03 C0
  add eax, eax

;42
  inc edx

;2B D0
  sub edx, eax

  ; At this point, 
  ;   edx = (index of highest bit set) + 1 - 2*(number of bits set)
  ; This is negative if and only if ecx was binary-heavy.

;D6
  salc           ; undocumented opcode. Sets al to 255 if carry flag 
                 ; is set, and to 0 otherwise. 

;C3
  ret

ลองออนไลน์!

ขอขอบคุณที่ปีเตอร์คอร์ดสำหรับการแนะนำการแทนที่ด้วยlzcntbsr


ดี ฉันได้เท่าที่ชัดเจนpopcntก่อนที่จะเลื่อนลงเพื่อดูคำตอบ แต่ไม่เคยคิดที่จะlzcntจัดการกับตัวเลขที่สำคัญตามที่คำถามต้องการ
Peter Cordes

มีวิธีใดบ้างที่จะประหยัดเงินสุทธิจากการใช้bsrแทนlzcnt(aka rep bsr)? คุณต้องใช้subแทนleaเพราะมันให้ 32-lzcnt (หรือออกจาก dst ที่ไม่ได้แก้ไขสำหรับ src = 0 บนฮาร์ดแวร์ Intel และ AMD ที่มีอยู่ทั้งหมด AMD ยังบันทึกพฤติกรรมนี้ แต่ Intel บอกว่าไม่ได้กำหนด ... อย่างไรก็ตาม OP บอกบวกซึ่งออกกฎ0)
Peter Cordes

1
ฉันคิดอย่างแน่นอนในบรรทัดเดียวกันกับ @Peter เนื่องจากความท้าทายจะ จำกัด อินพุตให้เป็นจำนวนเต็มบวกอย่างชัดเจน ในความเป็นจริงฉันมีวิธีแก้ปัญหาโดยใช้แบบร่างpopcntและbsrแต่มันมีขนาด 17 ไบต์ ฉันคิดว่ามันค่อนข้างดีเมื่อเทียบกับคำตอบ asm แรกที่ฉันเห็นแต่leaเคล็ดลับที่ชาญฉลาดนี้เต้นกางเกงออกจากที่ ฉันยังมองไปที่การเปรียบเทียบและbsf popcntแต่ฉันไม่เห็นวิธีการแก้ปัญหานี้สามารถเอาชนะแม้จะคำนึงถึง 1 ไบต์ที่คุณสามารถบันทึกได้โดยวางrepคำนำหน้า
โคดี้เกรย์

1
salcไม่เทียบเท่าการsetc al: ชุดหลังal1 ถ้า CF ตั้งไม่ถึง 255
Ruslan

1
ค่าเทียบเท่าที่แท้จริงsalcคือsbb al, alแต่คุณได้รับการประหยัดจาก 1 ไบต์เพื่อเข้ารหัส อย่างไรก็ตามมันได้รับการรับรองโดย AMD และได้รับการสนับสนุนอย่างกว้างขวางจาก Intel พร้อมกับผู้ช่วยจำแม้กระทั่งมาจากแผนที่รหัส P6 ของ Intel ดังนั้นอันนี้ค่อนข้างปลอดภัยจริงๆที่จะใช้ นอกจากนี้การปรับปรุงที่ดีที่นี่เพื่อคิดว่าจะใช้คำสั่งนั้น! นี่เป็นสิ่งที่ร่างดั้งเดิมของฉันทำยกเว้น (1) ฉันใช้รหัส x86-64 ดังนั้นจึงincเป็นสองเท่าในการเข้ารหัสและ (2) ฉันไม่ได้คิดsalcดังนั้นฉันจึงทำงานเดียวกันใน อีกต่อไปทาง น่าเสียดายที่ฉันสามารถโหวตได้เพียงครั้งเดียวเท่านั้น
โคดี้เกรย์

17

เยลลี่ 5 ไบต์

Bo-SR

ให้ผลลัพธ์เอาต์พุตที่ไม่ว่าง (ความจริง) หรือเอาต์พุตว่าง (เท็จ)

ลองออนไลน์!

มันทำงานอย่างไร

Bo-SR  Main link. Argument: n

B      Binary; convert n to base 2.
 o-    Compute the logical OR with -1, mapping 1 -> 1 and 0 -> -1.
   S   Take the sum s. We need to check if the sum is strictly positive.
    R  Range; yield [1, ..., s], which is non-empty iff s > 0.

ดี ฉันมีBo-Sแต่ฉันไม่สามารถหาอะตอมขนาด 1 ไบต์ที่จะแปลงค่าบวก / ไม่บวกเป็นความจริง / เท็จ ...
ETHproductions

ตรรกะหรือด้วย with1 ใช่มั้ย
ลินน์

@ ลินน์ใช่แน่นอน ขอบคุณ
Dennis


@cairdcoinheringaahing ขอบคุณ แต่Æṃไม่มีอยู่ตอนนั้น
Dennis

14

Python 2 , 35 ไบต์

lambda n:max('10',key=bin(n).count)

ลองออนไลน์!

คำตอบเก่า 38 ไบต์

เอาต์พุต0เป็นเท็จและ-2หรือ-1เป็นจริง

lambda n:~cmp(*map(bin(n).count,'10'))

ลองออนไลน์!


2
0 ผู้นำในการกลับมาของbinสาเหตุการแก้ไขปัญหานี้หรือไม่?
เงา

3
@shadow ไม่มีปัญหาเพราะวิธีการmaxทำงาน ในกรณีที่เสมอกันสูงสุดจะส่งกลับค่าแรกใน iterable ที่มีค่าสูงสุด รหัสนี้จะใช้ความจริงที่ว่าเพื่อให้แน่ใจว่า 1 binถูกส่งกลับในกรณีที่มีการผูกซึ่งอันที่จริงหมายความว่ามีคนมากกว่าศูนย์การตั้งแต่ศูนย์พิเศษถูกเพิ่มเข้ามาโดย จริง ๆ แล้วมันจะไม่ถูกต้องเมื่อเขียนด้วยวิธีนี้ถ้าไม่ใช่สำหรับศูนย์พิเศษ
FryAmTheEggman

@FryAmTheEggman นี่ก็เป็นจริงกับคำตอบเก่าซึ่งcmpผลตอบแทน0เมื่อพวกเขาทั้งสองเท่ากับ
Rod

11

อ็อกเทฟ , 18 ไบต์

@(n)mode(de2bi(n))

TIO ไม่ทำงานเนื่องจากไม่มีกล่องเครื่องมือการสื่อสาร มันสามารถนำมาทดสอบในคู่ออนไลน์

มันทำงานอย่างไร:

de2biแปลงตัวเลขทศนิยมที่จะเวกเตอร์ที่เป็นตัวเลขไบนารีไม่สตริงเป็นdec2binไม่

modeส่งคืนตัวเลขที่พบบ่อยที่สุดในเวกเตอร์ มันเริ่มต้นที่ต่ำที่สุดในกรณีที่ผูก

@(n)                % Anonymous function that takes a decimal number as input 'n'
    mode(        )  % Computes the most frequent digit in the vector inside the parentheses
         de2bi(n)   % Converts the number 'n' to a binary vector

กล่องเครื่องมือการสื่อสารเป็นส่วนมาตรฐานของ Octave หรือคล้ายกับห้องสมุดในภาษาอื่นหรือไม่
dcsohl

มันเป็นแพ็คเกจที่มาพร้อมกับการติดตั้ง คุณต้องโหลดมันเป็นพิเศษในการติดตั้งบางอย่างและมันจะโหลดโดยอัตโนมัติตามมาตรฐานในอื่น มันเป็นส่วนหนึ่งของมาตรฐานบน Octave-Online.net ดังนั้นฉันจึงใช้มันเป็นข้อมูลอ้างอิง (รหัสจะต้องทำงานในล่ามอย่างน้อยหนึ่งตัวที่มีอยู่ก่อนการท้า)
Stewie Griffin

9

JavaScript (ES6), 36 34 ไบต์

f=(n,x=0)=>n?f(n>>>1,x+n%2-.5):x>0

f=(n,x=0)=>n?f(n>>>1,x+=n%2-.5):x>0สำหรับ 35 ไบต์
OVS

ใช้n>>1แทนn>>>1การบันทึกไบต์เนื่องจากอินพุตไม่เคยเป็นค่าลบ
kamoroso94

@ kamoroso94 ขอบคุณ แต่แล้วมันจะล้มเหลวเมื่อ 2147483648
ETHproductions

@ETHproductions Darn และn/2|0ไม่ดีกว่า: /
kamoroso94


8

Mathematica ขนาด 22 ไบต์

ที่บันทึกไว้หนึ่งขอบคุณไบต์@MartinEnderและ@JungHwanMin

#>#2&@@#~DigitCount~2&

2
@@ผมคิดว่าโน้ตมัดมีลำดับความสำคัญสูงกว่า
Martin Ender

1
-1 ไบต์ (ตามที่ @MartinEnder ระบุไว้):#>#2&@@#~DigitCount~2&
JungHwan Min

7

Brachylogขนาด 6 ไบต์

ḃọtᵐ>₁

ลองออนไลน์!

คำอธิบาย

Example input: 13

ḃ        Base (default: binary): [1,1,0,1]
 ọ       Occurences:             [[1,3],[0,1]]
  tᵐ     Map Tail:               [3,1]
    >₁   Strictly decreasing list

เนื่องจากจะไม่มีการรวมเอาท์พุทของมันด้วยรายการตัวเลขที่มีเลขศูนย์นำหน้าเรารู้ว่าการเกิดขึ้นของ1จะเป็นอันดับแรกเสมอและการเกิดขึ้นของ0จะเป็นครั้งที่สองเสมอ



6

C (gcc) , 51 48 41 40 ไบต์

i;f(n){for(i=0;n;n/=2)i+=n%2*2-1;n=i>0;}

ลองออนไลน์!


จากคำชี้แจงของ OP คุณสามารถลบunsigned
musicman523

ตั้งแต่ nnn เป็นบวกคุณสามารถเปลี่ยนไปn>>=1 n/=2ฉันคิดว่าคุณสามารถใช้~nแทนn^-1ซึ่งควรอนุญาตให้คุณเปลี่ยน&&เป็น&
musicman523

สิ่งแปลก ๆ เกิดขึ้นเมื่อฉันแก้ไขความคิดเห็น - "nnn" หมายถึงnและไม่เคยคิดที่&&จะเปลี่ยนไป&ฉันไม่คิดว่ามันจะใช้ได้ แต่*ดูเหมือนว่ามันจะเปลี่ยนไปใช้งานได้
musicman523

@ musicman523 The &&เป็นเพียงการจัดการกับกรณีที่ไม่ได้ลงนาม แต่เนื่องจากฉันจะต้องจัดการกับจำนวนเต็มบวกฉันสามารถลบมันทั้งหมดเข้าด้วยกัน ดีมากที่พูด/=สั้นลงว่า>>=ขอบคุณ!
cleblanc

คุณสามารถบันทึกหนึ่งไบต์ที่เปลี่ยนแปลงไปn&1?++i:--1 i+=n%2*2-1คุณอาจสามารถกำจัดได้>0ด้วยการระบุว่าคุณจะแสดงผลเป็นศูนย์สำหรับเพลงที่หนักและไม่เป็นศูนย์สำหรับดนตรีที่ไม่หนัก
musicman523

6

R , 54 53 51 ไบต์

-1 ไบต์ขอบคุณ Max Lawnboy

n=scan();d=floor(log2(n))+1;sum(n%/%2^(0:d)%%2)*2>d

อ่านจาก stdin; ส่งคืนTRUEสำหรับเลขหนักไบนารี dคือจำนวนของเลขฐานสอง sum(n%/%2^(0:d)%%2คำนวณผลรวมหลัก (เช่นจำนวนของคน)

ลองออนไลน์!


เห็นคำตอบของคุณหลังจากโพสต์ของฉันเท่านั้น ... อย่างไรก็ตามคุณสามารถใช้log2(n)แทน log(n,2)การบันทึก 1 ไบต์
Maxim Mikhaylov

@ MaxLawnboy อ่าแน่นอน ขอบคุณ!
Giuseppe

นำออกไปอีก 12 ไบต์: codegolf.stackexchange.com/a/132396/59530
JAD

6

รหัสเครื่อง x86_64, 23 22 21 ไบต์

31 c0 89 fa 83 e2 01 8d 44 50 ff d1 ef 75 f3 f7 d8 c1 e8 1f c3

ถอดชิ้นส่วน:

  # zero out eax
  xor  %eax, %eax
Loop:
  # copy input to edx
  mov  %edi, %edx
  # extract LSB(edx)
  and  $0x1, %edx
  # increment(1)/decrement(0) eax depending on that bit
  lea -1(%rax,%rdx,2), %eax
  # input >>= 1
  shr  %edi
  # if input != 0: repeat from Loop
  jnz  Loop

  # now `eax < 0` iff the input was not binary heavy,
  neg %eax
  # now `eax < 0` iff the input was binary heavy (which means the MSB is `1`)
  # set return value to MSB(eax)
  shr  $31, %eax
  ret

ขอบคุณ @Ruslan, @PeterCordes สำหรับ-1byte!

ลองออนไลน์!


มีเหตุผลใด ๆ โดยเฉพาะเหตุผลที่คุณใช้8d 1fแทน89 fb?
Ruslan

2
คำถามจริงคือมีเหตุผลใดบ้างที่คุณใช้ไวยากรณ์ AT&T ที่น่ารังเกียจ?! นอกจากนี้การถอดประกอบและถอดชิ้นส่วนของคุณทั้งสองยอมรับว่าคุณมีadd eax, 2+ dec eaxแต่ความคิดเห็นของคุณขอแนะนำว่าคุณต้องการที่จะเพิ่มขึ้นไม่ได้ebx eax
โคดี้เกรย์

1
คุณสามารถแทนที่jnz Next/ add/ dec(7 ไบต์) ด้วยlea -1(%rax, %rbx, 2), %eax(4 ไบต์) สิ่งที่ต้องทำeax += 2*ebx - 1(เช่นในคำตอบรหัสเครื่อง x86 อื่น ๆ ) จากนั้นอยู่นอกลูปneg %eax(2 ไบต์) ก่อนที่จะเลื่อนบิตเครื่องหมายไปที่ด้านล่าง การประหยัดสุทธิ 1 ไบต์ หรือtest %eax,%eax/ setge %alยังจะทำงานถ้าค่าตอบแทนของคุณเป็นหรือbool int8_t
Peter Cordes

1
@ PeterCordes ฉันคิดว่าฉันรู้ว่าเกิดอะไรขึ้น แต่ฉันไม่แน่ใจ: ฉันอาจจะไม่ได้ลองlea -1(%rax,rbx,2)แต่อย่างเดียวlea -1(%eax,%eax,2)และเสีย bytes ด้วยวิธีนี้ .. อย่างไรก็ตามคุณทั้งคู่ถูกต้องฉันสามารถบันทึกไบต์เช่นนี้ได้ ขอบคุณมาก (ในทางกลับกันฉันจะเปลี่ยนleaเป็นระยะเวลาmovที่ฉันอยู่ที่นี่)!
ბიმო

1
@ moonheart08: ฉันไม่รู้เกี่ยวกับเรื่องนั้นในตอนนั้น แต่มีคนโพสต์คำตอบที่บันทึกไว้ 7 ไบต์
ბიმო

5

Perl 6 ,  32  30 ไบต์

{[>] .base(2).comb.Bag{qw<1 0>}}

ทดสอบมัน

{[>] .polymod(2 xx*).Bag{1,0}}

ทดสอบมัน

ขยาย:

{      # bare block lambda with implicit parameter 「$_」

  [>]  # reduce the following with &infix:« > »

    .polymod(2 xx *) # turn into base 2 (reversed) (implicit method call on 「$_」)
    .Bag\            # put into a weighted Set
    { 1, 0 }         # key into that with 1 and 0
                     # (returns 2 element list that [>] will reduce)
}


5

Haskell, 41 34

g 0=0
g n=g(div n 2)+(-1)^n
(<0).g

ถ้าnเป็นเลขคี่ใช้เวลาถ้ามันแม้จะใช้เวลา-1 1เพิ่มโทร recursive ด้วยและหยุดถ้าn/2 n = 0หากผลลัพธ์น้อยกว่า0จำนวนนั้นจะเป็นเลขฐานสองหนัก

ลองออนไลน์!

แก้ไข: @ Ørjan Johansen พบทางลัดและบันทึกไปแล้ว 7 ไบต์ ขอบคุณ!


mod n 2สามารถเป็นเพียงแค่nและมันเป็นไบต์ที่สั้นลงโดยไม่ต้องสะสม ลองออนไลน์!
Ørjan Johansen

5

เรติน่า , 37 34 ไบต์

.+
$*
+`(1+)\1
$1@
@1
1
+`.\b.

1+

ลองออนไลน์! ลิงก์มีกรณีทดสอบขนาดเล็ก (กรณีที่มีขนาดใหญ่กว่าอาจมีหน่วยความจำไม่เพียงพอ) แก้ไข: บันทึกแล้ว 3 ไบต์ด้วย @MartinEnder คำอธิบาย: ขั้นตอนแรกแปลงจากทศนิยมเป็น unary และอีกสองขั้นตอนต่อไปจะแปลงจาก unary เป็นไบนารี (เกือบจะตรงจากหน้าเลขคณิตของ unary บนวิกิ Retina ยกเว้นว่าฉันใช้@แทน0) ขั้นตอนที่สามมองหาคู่ของตัวละครที่แตกต่างกันซึ่งอาจเป็น@1หรือหรือ1@และลบออกจนกว่าจะไม่มีใครเหลืออยู่ ขั้นตอนสุดท้ายจะตรวจสอบ 1s ที่เหลืออยู่


${1}$+สามารถ หรือคุณอาจจะใช้!แทน0แล้วร่นไป01|10 .\b.
Martin Ender

@MartinEnder Huh $+ทำสิ่งที่ถูกต้องเมื่อรูปแบบมี|? ฉันสงสัยว่าฉันจะใช้มันก่อนหน้านี้ได้ไหม ...
นีล

2
ไม่$+โง่มากและใช้กลุ่มที่มีจำนวนมากที่สุดไม่ว่าจะใช้หรือไม่ก็ตาม มันมีประโยชน์สำหรับการเล่นกอล์ฟเมื่อคุณมีมากกว่าเก้ากลุ่มหรือในสถานการณ์แบบเดียวกับที่นี่และฉันไม่รู้ว่าทำไมฉันถึงใช้มันใน regex การผลิต
Martin Ender

5

R , 43 ไบต์

max(which(B<-intToBits(scan())>0))/2<sum(B)

ลองออนไลน์!

             intToBits(scan())              # converts to bits
          B<-                 >0            # make logical and assign to B
max(which(                      ))/2        # get the length of the trimmed binary and halve
                                    <sum(B) # test against the sum of bits

+1 โซลูชั่นที่ประณีต! ฉันไม่รู้ด้วยซ้ำว่าintToBits
Giuseppe

ออกไปอีก 4 ไบต์: codegolf.stackexchange.com/a/132396/59530
JAD

5

Kotlinขนาด 50 ไบต์

{i:Int->i.toString(2).run{count{it>'0'}>length/2}}

(Int) -> Booleanแลมบ์ดาประเภทโดยปริยาย เวอร์ชั่น 1.1 และสูงกว่าเพียง Int.toString(radix: Int)แต่เนื่องจากการใช้งานของ

น่าเสียดาย Kotlin runtime ของ TIO น่าจะเป็น 1.0.x ดังนั้นนี่คือสุนัขที่น่าเศร้าแทนที่จะใช้ลิงค์ของ TIO:


4

Pyth, 9 7 ไบต์

ehc2S.B

ลองที่นี่

ขอบคุณ -2 ถึงFryAmTheEggman


อีกวิธีที่ 9 ไบต์:>ysJjQ2lJ
KarlKastor

1
7 ไบต์แต่ฉันรู้สึกเหมือนยังคงมีบางสิ่งบางอย่างที่ควรจะสั้น ...
FryAmTheEggman

@FryAmTheEggman อืม ... นั่นใช้ได้เฉพาะกับโปรแกรมแบบเต็มเท่านั้น (ฉันรู้ว่ามีวิธีใช้.B!)
Erik the Outgolfer

4

R, 39 37 ไบต์

sum(intToBits(x<-scan())>0)>2+log2(x)

นี่คือการรวมกันของวิธีการที่ใช้โดย @MickyT และ @Giuseppe ช่วยประหยัดอีกสองสามไบต์

sum(intToBits(x) > 0)นับจำนวน1บิตและ2+log2(x)/2เป็นครึ่งหนึ่งของจำนวนบิตทั้งหมดเมื่อปัดเศษลง เราไม่ต้องปัดเศษเนื่องจากพฤติกรรมเมื่อค่าสองค่าเท่ากัน



4

Regex (ECMAScript), 85 73 71 ไบต์

^((?=(x*?)\2(\2{4})+$|(x*?)(\4\4xx)*$)(\2\4|(x*)\5\7\7(?=\4\7$\2)\B))*$

ลองออนไลน์!

คำอธิบายโดยDeadcode

เวอร์ชั่น 73 ไบต์ก่อนหน้านี้อธิบายไว้ด้านล่าง

^((?=(x*?)\2(\2{4})+$)\2|(?=(x*?)(\4\4xx)*$)(\4|\5(x*)\7\7(?=\4\7$)\B))+$

เนื่องจากข้อ จำกัด ของ ECMAScript regex ชั้นเชิงที่มีประสิทธิภาพมักจะเปลี่ยนหมายเลขหนึ่งครั้งในขณะที่รักษาค่าคงที่ของคุณสมบัติที่จำเป็นในทุกขั้นตอน ตัวอย่างเช่นในการทดสอบกำลังสองที่สมบูรณ์แบบหรือกำลังสองให้ลดจำนวนลงในขณะที่รักษากำลังสองหรือกำลังสอง (ตามลำดับ) ทุกขั้นตอน

นี่คือสิ่งที่โซลูชันนี้ทำในทุกขั้นตอน:

111100101ones>zeroes1

ones>zeroesones1>zeroes1

เมื่อขั้นตอนที่ทำซ้ำเหล่านี้ไม่สามารถไปได้อีกต่อไปผลลัพธ์สุดท้ายจะเป็นสตริงของ1บิตที่ต่อเนื่องกันซึ่งมีน้ำหนักมากและบ่งชี้ว่าหมายเลขเดิมนั้นหนักเกินไปหรือกำลัง 2 แสดงว่าหมายเลขเดิมไม่หนัก

และแน่นอนถึงแม้ว่าขั้นตอนเหล่านี้จะอธิบายไว้ข้างต้นในแง่ของการจัดการเกี่ยวกับการพิมพ์บนเลขฐานสองของตัวเลข

# For these comments, N = the number to the right of the "cursor", a.k.a. "tail",
# and "rightmost" refers to the big-endian binary representation of N.
^
(                          # if N is even and not a power of 2:
    (?=(x*?)\2(\2{4})+$)   # \2 = smallest divisor of N/2 such that the quotient is
                           # odd and greater than 1; as such, it is guaranteed to be
                           # the largest power of 2 that divides N/2, iff N is not
                           # itself a power of 2 (using "+" instead of "*" is what
                           # prevents a match if N is a power of 2).
    \2                     # N = N - \2. This changes the rightmost "10" to a "01".
|                          # else (N is odd or a power of 2)
    (?=(x*?)(\4\4xx)*$)    # \4+1 = smallest divisor of N+1 such that the quotient is
                           # odd; as such, \4+1 is guaranteed to be the largest power
                           # of 2 that divides N+1. So, iff N is even, \4 will be 0.
                           # Another way of saying this: \4 = the string of
                           # contiguous 1 bits from the rightmost part of N.
                           # \5 = (\4+1) * 2 iff N+1 is not a power of 2, else
                           # \5 = unset (NPCG) (iff N+1 is a power of 2), but since
                           #   N==\4 iff this is the case, the loop will exit
                           #   immediately anyway, so an unset \5 will never be used.
    (
        \4                 # N = N - \4. If N==\4 before this, it was all 1 bits and
                           # therefore heavy, so the loop will exit and match. This
                           # would work as "\4$", and leaving out the "$" is a golf
                           # optimization. It still works without the "$" because if
                           # N is no longer heavy after having \4 subtracted from it,
                           # this will eventually result in a non-match which will
                           # then backtrack to a point where N was still heavy, at
                           # which point the following alternative will be tried.
    |
        # N = (N + \4 - 2) / 4. This removes the rightmost "01". As such, it removes
        # an equal number of 0 bits and 1 bits (one of each) and the heaviness of N
        # is invariant before and after. This fails to match if N is a power of 2,
        # and in fact causes the loop to reach a dead end in that case.
        \5                 # N = N - (\4+1)*2
        (x*)\7\7(?=\4\7$)  # N = (N - \4) / 4 + \4
        \B                 # Assert N > 0 (this would be the same as asserting N > 2
                           # before the above N = (N + \4 - 2) / 4 operation).
    )
)+
$       # This can only be a match if the loop was exited due to N==\4.

2
ขณะที่สิ่งนี้ได้รับแรงบันดาลใจจากคำตอบของ Deadcodeแต่อัลกอริทึมนั้นแตกต่างกันมากพอที่ฉันรู้สึกว่าสมควรได้รับคำตอบแยกต่างหากแทนที่จะเป็นความคิดเห็น
Grimmy

2
นี่เป็นปรากฎการณ์และสิ่งที่ฉันต้องการเห็น (มีคนเป่า regex ของฉันออกจากน้ำด้วยอัลกอริทึมที่กระชับกว่านี้) แต่ความคิดเห็นของคุณไม่ได้อธิบายเลยและ regex รุ่น 73 ไบต์ที่แสดงความคิดเห็นไม่สามารถใช้งาน\5ได้ ฉันได้ศึกษาสิ่งนี้และอธิบายและแสดงความคิดเห็นในคำตอบของฉัน (เนื่องจาก StackExchange ไม่อนุญาตให้มีการตอบกลับแบบหลายบรรทัด)
Deadcode

4

Regex (ECMAScript), 183 ไบต์

นี่เป็นอีกปัญหาที่น่าสนใจในการแก้ไขด้วย ECMA regex วิธี "ชัดเจน" ในการจัดการสิ่งนี้คือการนับจำนวน1บิตและเปรียบเทียบกับจำนวนบิตทั้งหมด แต่คุณไม่สามารถนับสิ่งต่าง ๆ โดยตรงใน ECMAScript regex - การขาดการอ้างอิงย้อนกลับแบบถาวรหมายความว่าอาจมีเพียงหนึ่งหมายเลขเท่านั้นที่สามารถแก้ไขในลูปและในแต่ละขั้นตอนจะสามารถลดลงได้เท่านั้น

อัลกอริทึม unary นี้ทำงานดังนี้:

  1. ใช้สแควร์รูทของกำลังที่ใหญ่ที่สุดของ 2 ที่พอดีกับ N และสังเกตว่าสแควร์รูทนั้นสมบูรณ์แบบหรือต้องถูกปัดเศษลง จะใช้ในภายหลัง
  2. ในลูปให้ย้าย1บิตที่มีนัยสำคัญที่สุดไปยังตำแหน่งที่มีนัยสำคัญน้อยที่สุดที่มี0บิต แต่ละขั้นตอนเหล่านี้เป็นการลบ ในตอนท้ายของการวนรอบจำนวนที่เหลืออยู่ (ตามที่มันจะถูกแสดงในรูปแบบไบนารี) คือสตริงของ1s ที่ไม่มี0s การดำเนินการเหล่านี้จะทำจริงในเอกภาพ; เป็นเพียงแนวคิดที่ว่าพวกเขากำลังทำในรูปแบบไบนารี
  3. เปรียบเทียบ "สตริงไบนารีของ1s" นี้กับสแควร์รูทที่ได้รับก่อนหน้านี้ หากสแควร์รูทต้องถูกปัดเศษลงให้ใช้เวอร์ชันสองเท่า สิ่งนี้ทำให้มั่นใจได้ว่า "ไบนารีสตริงของ1s" จำเป็นต้องมีมากกว่าครึ่งเลขฐานสองเป็นจำนวน N เพื่อให้มีการแข่งขันครั้งสุดท้าย

ที่จะได้รับรากที่แตกต่างจากขั้นตอนวิธีการคูณอธิบายสั้น ๆ ในของฉันหมายเลขร็อคโคโพสต์ regexถูกนำมาใช้ เพื่อระบุ0บิตที่มีนัยสำคัญน้อยที่สุดอัลกอริทึมการหารที่อธิบายสั้น ๆ ในการโพสต์เลข regexของฉันจะถูกนำมาใช้ เหล่านี้เป็นสปอยเลอร์ ดังนั้นไม่ได้อ่านใด ๆ ต่อไปถ้าคุณไม่ต้องการขั้นสูงบางอย่างเอกมายากล regex มากมายสำหรับคุณ หากคุณต้องการที่จะหาวิธีแก้ปัญหานี้ด้วยตัวเองฉันขอแนะนำให้เริ่มต้นด้วยการแก้ปัญหาบางอย่างในรายการปัญหาที่แนะนำติดแท็กสปอยเลอร์ติดต่อกันในบทความก่อนหน้านี้และพยายามหาข้อมูลเชิงลึกทางคณิตศาสตร์อย่างอิสระ

ไม่มีความกังวลใจเพิ่มเติม regex:

^(?=.*?(?!(x(xx)+)\1*$)(x)*?(x(x*))(?=(\4*)\5+$)\4*$\6)(?=(((?=(x(x+)(?=\10$))*(x*))(?!.*$\11)(?=(x*)(?=(x\12)*$)(?=\11+$)\11\12+$)(?=.*?(?!(x(xx)+)\14*$)\13(x*))\16)*))\7\4(.*$\3|\4)

ลองออนไลน์!

# For the purposes of these comments, the input number = N.
^
# Take the floor square root of N
(?=
    .*?
    (?!(x(xx)+)\1*$)    # tail = the largest power of 2 less than tail
    (x)*?               # \3 = nonzero if we will need to round this square root
                        #      up to the next power of two
    (x(x*))             # \4 = potential square root; \5 = \4 - 1
    (?=
        (\4*)\5+$       # Iff \4*\4 == our number, then the first match here must result in \6==0
    )
    \4*$\6              # Test for divisibility by \4 and for \6==0 simultaneously
)
# Move all binary bits to be as least-significant as possible, e.g. 11001001 -> 1111
(?=
    (                                 # \7 = tool for making tail = the result of this move
        (
            (?=
                (x(x+)(?=\10$))*(x*)  # \11 = {divisor for getting the least-significant 0 bit}-1
            )
            (?!.*$\11)                # Exit the loop when \11==0
            (?=
                (x*)                  # \12 = floor((tail+1) / (\11+1)) - 1
                (?=(x\12)*$)          # \13 = \12+1
                (?=\11+$)
                \11\12+$
            )
            (?=
                .*?
                (?!(x(xx)+)\14*$)     # tail = the largest power of 2 less than tail
                \13                   # tail -= \13
                (x*)                  # \16 = tool to move the most-significant 1 bit to the
                                      # least-significant 0 bit available spot for it
            )
            \16
        )*
    )
)
\7                  # tail = the result of the move
\4                  # Assert that \4 is less than or equal to the result of the move
(
    .*$\3
|
    \4              # Double the value of \4 to compare against if \3 is non-empty,
                    # i.e. if we had an even number of total digits.
)


3

Bo-Sสามารถใช้ในการคำนวณ "น้ำหนัก" ไบนารีของอินพุต แต่น่าเสียดายที่วิธีที่สั้นที่สุดในการใช้ที่ดูเหมือนจะเป็นBo-S>0...
ETHproductions

@ETHproductions ใช่ยังไม่มีอะตอม "เป็นบวก"
Erik the Outgolfer

ดูเหมือนจะได้ผลดี: P
ETHproductions

3

J , 12 ไบต์

(+/>-:@#)@#:

J รันคำกริยาจากขวาไปซ้ายดังนั้นเรามาเริ่มกันที่จุดสิ้นสุดและดำเนินการต่อไปจนถึงจุดเริ่มต้น

คำอธิบาย

         #:       NB. Convert input to list of bits
       -:@#       NB. Half (-:) the (@) length (#)
          >       NB. Greater than 
         +/       NB. Sum (really plus (+) reduce (/)

1
(#<2*+/)@#:ควรบันทึก 1 เว้นแต่ฉันจะพลาดบางสิ่ง
FrownyFrog




2

Python 2 , 44 ไบต์

f=lambda n,c=0:f(n/2,c+n%2*2-1)if n else c>0

ลองออนไลน์!

คำตอบเก่า 47 ไบต์

c,n=0,input()
while n:c+=n%2*2-1;n/=2
print c>0

นี้เป็นเพียงพอร์ตของของ @ cleblanc คำตอบ มันยาวกว่าคำตอบ Python อื่น ๆ แต่ฉันคิดว่ามันคุ้มค่ากับการโพสต์เพราะมันเป็นวิธีการที่แตกต่างกันโดยสิ้นเชิงในการค้นหาคำตอบ

ลองออนไลน์!


2

C #, 82 ไบต์

n=>{var s=System.Convert.ToString(n,2);return s.Replace("0","").Length>s.Length/2}

คุณสามารถเล็มได้มากกว่านี้โดยใช้สตริงเป็น IEnumerable <char> n=>{var s=Convert.ToString(n,2);return s.Count(c=>c=='1')>s.Length/2;}
GalacticCowboy

@GalacticCowboy นั่นเพิ่ม 11 ไบต์เพราะคุณต้องผ่านการรับรองConvertและรวมถึงusing System.Linq;(เขียนให้สั้นลงnamespace System.Linq{}) แนวคิดที่ดีไม่ได้โกนเพียงพอที่จะรับประกันการประหยัดในกรณีนี้
TheLethalCoder
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.