ตัวหารร่วมมาก


40

งานของคุณคือการคำนวณตัวหารร่วมมาก (GCD) ที่ยิ่งใหญ่ที่สุดของจำนวนเต็มสองจำนวนที่ได้รับในโค้ดน้อยที่สุดเท่าที่จะเป็นไปได้

คุณสามารถเขียนโปรแกรมหรือฟังก์ชั่นรับอินพุตและส่งคืนเอาต์พุตผ่านวิธีมาตรฐานที่ยอมรับของเรา (รวมถึง STDIN / STDOUT, พารามิเตอร์ฟังก์ชัน / ค่าส่งคืน, อาร์กิวเมนต์บรรทัดคำสั่ง ฯลฯ )

อินพุตจะเป็นจำนวนเต็มสองจำนวนที่ไม่เป็นลบ คุณควรจะสามารถจัดการกับช่วงเต็มได้รับการสนับสนุนโดยประเภทจำนวนเต็มเริ่มต้นของภาษาของคุณหรือช่วง[0,255]ใดก็ตามที่มากกว่า คุณรับประกันได้ว่าอย่างน้อยหนึ่งอินพุตจะไม่ใช่ศูนย์

คุณไม่ได้รับอนุญาตให้ใช้บิวด์อินที่คำนวณ GCD หรือ LCM (ตัวคูณร่วมน้อย)

ใช้กฎมาตรฐานของ

กรณีทดสอบ

0 2     => 2
6 0     => 6
30 42   => 6
15 14   => 1
7 7     => 7
69 25   => 1
21 12   => 3
169 123 => 1
20 142  => 2
101 202 => 101

1
หากเราอนุญาตให้ asm มีอินพุตในสิ่งที่รีจิสเตอร์นั้นสะดวกและผลลัพธ์ในสิ่งที่รีจิสเตอร์อำนวยความสะดวกเราก็ควรจะอนุญาตให้ใช้ฟังก์ชั่นได้อย่างแน่นอนหรือแม้กระทั่งการแยกส่วนของโค้ด ทำให้คำตอบของฉันฟังก์ชั่นที่สมบูรณ์จะเพิ่มประมาณ 4B ด้วยการประชุมเรียกการลงทะเบียนเช่น vectorbit 32 บิตของ MS (หนึ่ง xchg eax หนึ่ง mov และ ret) หรือมากกว่าด้วยการประชุมเรียกกอง
Peter Cordes

@PeterCordes ขออภัยฉันควรเจาะจงมากขึ้น คุณสามารถเขียนรหัสที่จำเป็นสำหรับหมีได้ทั้งหมด แต่ถ้าคุณใจดีที่จะใส่วิธีเรียกใช้โค้ดดังกล่าวมันจะดีมาก
Mike Shlanta

ดังนั้นนับเพียงรหัส gcd แต่ให้รหัสโดยรอบเพื่อให้ผู้คนสามารถยืนยัน / ทดลอง / ปรับปรุงได้ BTW กรณีทดสอบของคุณที่มีค่าศูนย์เป็นหนึ่งในสองอินพุตที่ทำลายคำตอบของรหัสเครื่อง x86 หารด้วยศูนย์ทำให้เกิดข้อยกเว้นฮาร์ดแวร์ บน Linux SIGFPEกระบวนการของคุณได้รับ
Peter Cordes

3
@CodesInChaos ข้อ จำกัด ของหน่วยความจำและเวลามักจะถูกละเว้นตราบใดที่อัลกอริทึมสามารถทำได้ในหลักการจัดการอินพุตทั้งหมด กฎนี้มีขึ้นเพื่อหลีกเลี่ยงคนที่ จำกัด การใช้งานโดยพลการสำหรับลูปที่ทำเทียม จำกัด อัลกอริทึมไปยังอินพุตขนาดเล็ก ฉันไม่เห็นเลยว่าความผันแปรนี้เกิดขึ้นได้อย่างไร
Martin Ender

1
gcd (0, n) ไม่ใช่ข้อผิดพลาด n
RosLuP

คำตอบ:


37

จอประสาทตา , 16

^(.+)\1* \1+$
$1

นี่ไม่ได้ใช้อัลกอริทึมของ Euclid เลย แต่จะพบ GCD โดยใช้กลุ่มการจับคู่ regex

ลองออนไลน์ - ตัวอย่างนี้คำนวณ GCD (8,12)

ป้อนข้อมูลเป็นจำนวนเต็ม 2 รายการคั่นด้วยช่องว่าง โปรดทราบว่า I / O เป็นเอกภาพ หากไม่เป็นที่ยอมรับเราสามารถทำสิ่งนี้ได้:

เรติน่า 30

\d+
$*
^(.+)\1* \1+$
$1
1+
$.&

ลองออนไลน์

ตามที่ @ MartinBüttnerชี้ให้เห็นสิ่งนี้แยกออกจากกันสำหรับคนจำนวนมาก อย่างน้อยที่สุดอินพุตของ INT_MAX จะต้องมีการจัดสรรสตริง 2GB


2
ฉันต้องการที่จะลงคะแนนเสียงให้มากขึ้นนี้
MickyT

ควรจะดีกับช่วงหมายเลขตอนนี้ ฉันได้เปลี่ยนสเป็ค (ด้วยการอนุญาต OPs) เพื่อต้องการเฉพาะช่วงจำนวนธรรมชาติของภาษา (หรือ [0,255] ถ้ามันมากกว่า) คุณจะได้ให้การสนับสนุนศูนย์แม้ว่า แต่ฉันคิดว่าการเปลี่ยนแปลงของคุณ+เพื่อ*s ควรจะทำอย่างไร และคุณสามารถตัดทอนขั้นตอนสุดท้ายของรหัสยาวลงได้1อย่างมากโดยลดให้เหลือ
Martin Ender

2
สำหรับการอ้างอิงในอนาคตฉันเพิ่งพบโซลูชันทางเลือก 16 ไบต์ที่ทำงานกับอินพุตจำนวนหนึ่ง (รวมถึงหนึ่ง) ดังนั้นมันอาจมีประโยชน์มากกว่าในบริบทอื่น: retina.tryitonline.net/
Martin Ender

1
เพิ่งสังเกตเห็นว่าการแก้ปัญหาของคุณหรือของคุณในความคิดเห็นของฉันข้างต้นไม่ได้ต้องการ^เพราะเป็นไปไม่ได้ที่การแข่งขันจะล้มเหลวจากตำแหน่งเริ่มต้น
Martin Ender

28

รหัสเครื่อง i386 (x86-32), 8 ไบต์ (9B สำหรับการลงนาม)

+ 1B หากเราจำเป็นต้องจัดการb = 0กับอินพุต

รหัสเครื่อง amd64 (x86-64), 9 ไบต์ (10B สำหรับผู้ลงนาม, หรือ14B 13B สำหรับจำนวนเต็ม 64b ที่ลงชื่อหรือไม่ได้ลงนาม)

10 9B สำหรับ amd64 ที่ไม่ได้ลงชื่อเมื่อมีการป้อนข้อมูลด้วย = 0


ปัจจัยการผลิตเป็น 32bit ไม่ใช่ศูนย์ลงนามจำนวนเต็มในและeax เอาท์พุทecxeax

## 32bit code, signed integers:  eax, ecx
08048420 <gcd0>:
 8048420:       99                      cdq               ; shorter than xor edx,edx
 8048421:       f7 f9                   idiv   ecx
 8048423:       92                      xchg   edx,eax    ; there's a one-byte encoding for xchg eax,r32.  So this is shorter but slower than a mov
 8048424:       91                      xchg   ecx,eax    ; eax = divisor(from ecx), ecx = remainder(from edx), edx = quotient(from eax) which we discard
    ; loop entry point if we need to handle ecx = 0
 8048425:       41                      inc    ecx        ; saves 1B vs. test/jnz in 32bit mode
 8048426:       e2 f8                   loop   8048420 <gcd0>
08048428 <gcd0_end>:
 ; 8B total
 ; result in eax: gcd(a,0) = a

ecx = 0โครงสร้างวงนี้ล้มเหลวในการทดสอบกรณีที่ ( divทำให้การ#DEประมวลผลของฮาร์ดแวร์หารด้วยศูนย์ (บน Linux เคอร์เนลจะส่งมอบSIGFPE(ข้อยกเว้นจุดลอย)) หากจุดเข้าใช้วนรอบนั้นอยู่ตรงหน้าincเราจะหลีกเลี่ยงปัญหารุ่น x86-64 สามารถจัดการได้ ฟรีดูด้านล่าง

คำตอบไมค์ Shlanta เป็นจุดเริ่มต้นสำหรับการนี้ ห่วงฉันจะเป็นสิ่งเดียวกันเป็นของเขา แต่สำหรับจำนวนเต็มลงนามเพราะcdqเป็นหนึ่งใน byter xor edx,edxสั้นกว่า และใช่มันทำงานได้อย่างถูกต้องโดยมีอินพุตหนึ่งหรือทั้งสองเป็นลบ เวอร์ชันของ Mike จะทำงานเร็วขึ้นและใช้พื้นที่น้อยลงในแคช uop ( xchgคือ 3 uops บน Intel CPUs และloopช้ามากใน CPUs ส่วนใหญ่ ) แต่รุ่นนี้จะชนะด้วยขนาดรหัสเครื่อง

ฉันไม่ได้สังเกตในตอนแรกว่าคำถามนั้นต้องการ32 บิตที่ไม่ได้ลงชื่อ กลับไปที่xor edx,edxแทนที่จะcdqเสียค่าใช้จ่ายหนึ่งไบต์ divมีขนาดเท่าidivกันและทุกอย่างอื่นสามารถเหมือนเดิมได้ ( xchgสำหรับการเคลื่อนย้ายข้อมูลและinc/loopยังใช้งานได้)

ที่น่าสนใจสำหรับตัวถูกดำเนินการขนาด 64 บิต ( raxและrcx) รุ่นที่เซ็นชื่อและไม่ได้ลงชื่อมีขนาดเท่ากัน เวอร์ชันที่ลงนามต้องการคำนำหน้า REX สำหรับcqo(2B) แต่รุ่นที่ไม่ได้ลงชื่อยังคงสามารถใช้ 2B xor edx,edxได้

ในรหัส 64 บิตinc ecxคือ 2B: ไบต์เดียวinc r32และdec r32opcodes ถูก repurposed เป็นคำนำหน้า REX inc/loopจะไม่บันทึกรหัสขนาดในโหมด 64bit test/jnzดังนั้นคุณอาจได้เป็นอย่างดี การดำเนินงานในจำนวนเต็ม 64bit เพิ่มอีกหนึ่งไบต์ต่อการเรียนการสอนในคำนำหน้า REX ยกเว้นหรือloop jnzมันเป็นไปได้สำหรับส่วนที่เหลือที่จะมีศูนย์ทั้งหมดใน 32b ต่ำ (เช่นgcd((2^32), (2^32 + 1))) ดังนั้นเราจึงจำเป็นที่จะทดสอบ RCX test ecx,ecxทั้งหมดและไม่สามารถบันทึกไบต์ด้วย อย่างไรก็ตามjrcxzinsn ที่ช้ากว่านั้นมีเพียง 2B และเราสามารถวางไว้ที่ด้านบนของลูปเพื่อจัดการecx=0กับรายการ :

## 64bit code, unsigned 64 integers:  rax, rcx
0000000000400630 <gcd_u64>:
  400630:       e3 0b                   jrcxz  40063d <gcd_u64_end>   ; handles rcx=0 on input, and smaller than test rcx,rcx/jnz
  400632:       31 d2                   xor    edx,edx                ; same length as cqo
  400634:       48 f7 f1                div    rcx                      ; REX prefixes needed on three insns
  400637:       48 92                   xchg   rdx,rax
  400639:       48 91                   xchg   rcx,rax
  40063b:       eb f3                   jmp    400630 <gcd_u64>
000000000040063d <gcd_u64_end>:
## 0xD = 13 bytes of code
## result in rax: gcd(a,0) = a

โปรแกรมทดสอบmainที่รันได้เต็มรูปแบบรวมถึงที่รันprintf("...", gcd(atoi(argv[1]), atoi(argv[2])) ); ซอร์สและเอาต์พุต asm บน Godbolt Compiler Explorerสำหรับเวอร์ชัน 32 และ 64b ทดสอบและการทำงานสำหรับ 32bit ( -m32) 64bit ( -m64) และx32 ABI (-mx32 )

รวมอยู่ด้วย: รุ่นที่ใช้การลบซ้ำ ๆ เท่านั้นซึ่งเป็น 9B สำหรับผู้ที่ไม่ได้ลงชื่อแม้สำหรับโหมด x86-64 และสามารถรับอินพุตหนึ่งตัวในการลงทะเบียนโดยพลการ อย่างไรก็ตามมันไม่สามารถจัดการอินพุตที่เป็น 0 ในรายการ (ตรวจพบเมื่อsubสร้างศูนย์ซึ่ง x - 0 ไม่เคยทำ)

GNU C inline asm ซอร์สสำหรับรุ่น 32 บิต (คอมไพล์ด้วยgcc -m32 -masm=intel)

int gcd(int a, int b) {
    asm (// ".intel_syntax noprefix\n"
        // "jmp  .Lentry%=\n" // Uncomment to handle div-by-zero, by entering the loop in the middle.  Better: `jecxz / jmp` loop structure like the 64b version
        ".p2align 4\n"                  // align to make size-counting easier
         "gcd0:   cdq\n\t"              // sign extend eax into edx:eax.  One byte shorter than xor edx,edx
         "        idiv    ecx\n"
         "        xchg    eax, edx\n"   // there's a one-byte encoding for xchg eax,r32.  So this is shorter but slower than a mov
         "        xchg    eax, ecx\n"   // eax = divisor(ecx), ecx = remainder(edx), edx = garbage that we will clear later
         ".Lentry%=:\n"
         "        inc     ecx\n"        // saves 1B vs. test/jnz in 32bit mode, none in 64b mode
         "        loop    gcd0\n"
        "gcd0_end:\n"
         : /* outputs */  "+a" (a), "+c"(b)
         : /* inputs */   // given as read-write outputs
         : /* clobbers */ "edx"
        );
    return a;
}

โดยปกติแล้วฉันจะเขียนฟังก์ชันทั้งหมดใน asm แต่ GNU C inline asm ดูเหมือนจะเป็นวิธีที่ดีที่สุดในการรวมตัวอย่างที่สามารถมี / ส่งออกในสิ่งที่เราเลือก อย่างที่คุณเห็น GNU C inline asm ไวยากรณ์ทำให้ asm น่าเกลียดและมีเสียงดัง นอกจากนี้ยังเป็นวิธีที่จริงยากที่จะเรียนรู้ asm

มันจะรวบรวมและทำงานใน.att_syntax noprefixโหมดจริงเพราะ insns ทั้งหมดที่ใช้เป็นตัวถูกดำเนินการเดี่ยว / ไม่มีxchgเลย ไม่ใช่การสังเกตที่มีประโยชน์จริงๆ


2
@ MikeShlanta: ขอบคุณ หากคุณต้องการเพิ่มประสิทธิภาพ asm โปรดดูคำตอบของฉันบางส่วนใน stackoverflow :)
Peter Cordes

2
@ MikeShlanta: ฉันพบการใช้งานjrcxzหลังจากทั้งหมดในรุ่น uint64_t :) นอกจากนี้ไม่ได้สังเกตว่าคุณได้ระบุผู้ที่ไม่ได้ลงชื่อดังนั้นฉันจึงนับจำนวนไบต์ด้วยเช่นกัน
Peter Cordes

ทำไมคุณไม่สามารถใช้เอjecxzฟเฟกต์แบบเดียวกันกับรุ่น 32 บิตได้?
โคดี้เกรย์

1
@CodyGray: inc/loopเป็น 3 ไบต์ในรุ่น 32 บิต แต่ 4B ในรุ่น 64 บิต ซึ่งหมายความว่าว่าในรุ่น 64 บิตเท่านั้นจะไม่เสียค่าใช้จ่ายไบต์เป็นพิเศษในการใช้jrcxzและการแทนjmp inc / loop
Peter Cordes

คุณไม่สามารถชี้ตรงกลางเป็นรายการได้หรือไม่
l4m2

14

Hexagonyขนาด 17 ไบต์

?'?>}!@<\=%)>{\.(

กางออก:

  ? ' ?
 > } ! @
< \ = % )
 > { \ .
  ( . .

ลองออนไลน์!

ติดตั้งเข้ากับความยาวด้าน 3 ได้อย่างรวดเร็ว ในตอนท้ายการปัดสองไบท์ออกไปนั้นไม่ได้ ... ฉันไม่มั่นใจว่ามันจะดีที่สุด แต่ฉันแน่ใจว่ามันใกล้เคียง

คำอธิบาย

การใช้อัลกอริทึมแบบยุคลิดอีกอันหนึ่ง

โปรแกรมใช้หน่วยความจำสามขอบซึ่งฉันจะเรียกA , BและCโดยที่ตัวชี้หน่วยความจำ (MP) เริ่มต้นดังที่แสดง:

ป้อนคำอธิบายรูปภาพที่นี่

นี่คือแผนภาพการควบคุมการไหล:

ป้อนคำอธิบายรูปภาพที่นี่

โฟลว์คอนโทรลเริ่มต้นบนพา ธ สีเทาด้วยบิตเชิงเส้นสั้น ๆ สำหรับอินพุต:

?    Read first integer into memory edge A.
'    Move MP backwards onto edge B.
?    Read second integer into B.

โปรดทราบว่าในขณะนี้โค้ดจะล้อมรอบขอบไปที่<มุมซ้าย นี้<ทำหน้าที่เป็นสาขา หากขอบปัจจุบันเป็นศูนย์ (เช่นอัลกอริธึมแบบยุคลิดยุติ) IP จะเบี่ยงเบนไปทางซ้ายและเข้าสู่เส้นทางสีแดง มิฉะนั้นการคำนวณซ้ำของอัลกอริทึมแบบยุคลิดจะถูกคำนวณบนเส้นทางสีเขียว

ก่อนอื่นเราจะพิจารณาเส้นทางสีเขียว โปรดทราบว่า>และ\ทำหน้าที่เหมือนกระจกเงาซึ่งเพียงเบี่ยงเบนตัวชี้คำสั่ง โปรดทราบว่าการควบคุมการไหลล้อมรอบขอบสามครั้งหนึ่งครั้งจากด้านล่างไปด้านบนหนึ่งครั้งจากมุมขวาไปยังแถวด้านล่างและในที่สุดจากมุมขวาล่างถึงมุมซ้ายเพื่อตรวจสอบสภาพอีกครั้ง ยังทราบว่า.ไม่มี ops

ที่เหลือรหัสเชิงเส้นต่อไปนี้สำหรับการทำซ้ำเดียว:

{    Move MP forward onto edge C.
'}   Move to A and back to C. Taken together this is a no-op.
=    Reverse the direction of the MP so that it now points at A and B. 
%    Compute A % B and store it in C.
)(   Increment, decrement. Taken together this is a no-op, but it's
     necessary to ensure that IP wraps to the bottom row instead of
     the top row.

ตอนนี้เรากลับมาที่จุดเริ่มต้นยกเว้นว่าขอบทั้งสามได้เปลี่ยนบทบาทของพวกเขาไปเรื่อย ๆ ( ตอนนี้Cดั้งเดิมรับหน้าที่เป็นBและBต้นฉบับเป็นบทบาทของA ... ) ในความเป็นจริงเราได้ย้ายอินพุตAและBด้วยBและA % Bตามลำดับ

เมื่อA % B(บนขอบC ) เป็นศูนย์ GCD สามารถพบได้บนขอบB อีกครั้งที่>เบี่ยงเบน IP ดังนั้นบนเส้นทางสีแดงที่เราเรียกใช้:

}    Move MP to edge B.
!    Print its value as an integer.
@    Terminate the program.

9

รหัสเครื่อง x86 ขนาดเล็กแบบ end-endian 32 บิตขนาด 14 ไบต์

สร้างโดยใช้ nasm -f bin

d231 f3f7 d889 d389 db85 f475

    gcd0:   xor     edx,edx
            div     ebx
            mov     eax,ebx
            mov     ebx,edx
            test    ebx,ebx
            jnz     gcd0

4
ผมได้ลงนี้ถึง 8 ไบต์โดยใช้cdqและลงนามidivและหนึ่งไบต์แทนxchg eax, r32 movสำหรับรหัส 32 บิต: inc/loopแทนtest/jnz(ฉันไม่เห็นวิธีใช้jecxzและไม่มีjecxnz) ฉันโพสต์เวอร์ชันสุดท้ายเป็นคำตอบใหม่เนื่องจากฉันคิดว่าการเปลี่ยนแปลงมีขนาดใหญ่พอที่จะพิสูจน์ได้
Peter Cordes

9

T-SQL, 153 169ไบต์

มีคนพูดถึงภาษาที่แย่ที่สุดสำหรับการเล่นกอล์ฟ

CREATE FUNCTION G(@ INT,@B INT)RETURNS TABLE RETURN WITH R AS(SELECT 1D,0R UNION ALL SELECT D+1,@%(D+1)+@B%(D+1)FROM R WHERE D<@ and D<@b)SELECT MAX(D)D FROM R WHERE 0=R

สร้างฟังก์ชันที่มีค่าของตารางที่ใช้คิวรีแบบเรียกซ้ำเพื่อหาตัวหารทั่วไป จากนั้นก็จะส่งกลับสูงสุด ตอนนี้ใช้ขั้นตอนวิธี Euclidean เพื่อตรวจสอบ GCD ที่ได้มาจากคำตอบของฉันที่นี่

ตัวอย่างการใช้งาน

SELECT * 
FROM (VALUES
        (15,45),
        (45,15),
        (99,7),
        (4,38)
    ) TestSet(A, B)
    CROSS APPLY (SELECT * FROM G(A,B))GCD

A           B           D
----------- ----------- -----------
15          45          15
45          15          15
99          7           1
4           38          2

(4 row(s) affected)

1
พระเยซูที่ verbose
Cyoce

9

เยลลี่ขนาด 7 ไบต์

ṛß%ðḷṛ?

การใช้งานแบบเรียกซ้ำของอัลกอริทึมแบบยุคลิด ลองออนไลน์!

หากไม่ได้ถูกห้ามใช้งานบิวด์อินg(1 ไบต์ GCD ในตัว) จะได้คะแนนที่ดีกว่า

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

ṛß%ðḷṛ?  Main link. Arguments: a, b

   ð     Convert the chain to the left into a link; start a new, dyadic chain.
 ß       Recursively call the main link...
ṛ %        with b and a % b as arguments.
     ṛ?  If the right argument (b) is non-zero, execute the link.
    ḷ    Else, yield the left argument (a).

ที่เกือบจะรู้สึกเหมือนการโกงฮ่าฮ่าฉันอาจต้องระบุคำตอบที่ไม่สามารถใช้ butlins ...
Mike Shlanta

13
หากคุณตัดสินใจที่จะทำคุณควรทำอย่างรวดเร็ว ขณะนี้จะทำให้คำตอบสามข้อเป็นโมฆะ
เดนนิส

โปรดสังเกตว่าเขาระบุความยาวเป็นไบต์ - อักขระเหล่านั้นส่วนใหญ่> 1 ไบต์ใน UTF8
cortices

8
@cortices ใช่การแข่งขันกอล์ฟ code ทั้งหมดจะทำคะแนนเป็นไบต์ อย่างไรก็ตาม Jelly ไม่ได้ใช้ UTF-8 แต่เป็นหน้ารหัสที่กำหนดเองที่เข้ารหัสอักขระ 256 ตัวแต่ละตัวที่เข้าใจเป็นไบต์เดียว
Dennis

@Dennis ah ฉลาด
cortices

7

Haskell, 19 ไบต์

a#0=a
a#b=b#rem a b

ตัวอย่างการใช้งาน: ->45 # 355

ยุคลิดอีกครั้ง

PS: แน่นอนว่ามีในตัวgcdด้วย


คุณควรอธิบายกลอุบายที่กลับคำสั่งอินพุตเพื่อหลีกเลี่ยงการตรวจสอบเงื่อนไข
ภูมิใจ haskeller

@proudhaskeller: อะไรหลอก? ทุกคนใช้อัลกอริทึมนี้เช่นหยุด0หรือดำเนินการกับโมดูลัส
nimi

เนฟมินด์ทุกคนใช้เคล็ดลับ
ภูมิใจ haskeller

นี่คือสนามกอล์ฟที่น้อยกว่าเกือบจะเหมือนกับสิ่งที่อยู่ในนั้นPrelude
Michael Klein

6

Python 3, 31

บันทึกแล้ว 3 ไบต์ด้วย Sp3000

g=lambda a,b:b and g(b,a%b)or a

3
ใน Python 3.5+:from math import*;gcd
Sp3000

@ Sp3000 ดีฉันไม่ทราบว่าพวกเขาย้ายไปคณิตศาสตร์
Morgan Thrapp

1
ในขณะที่คุณกำลังที่จะ:g=lambda a,b:b and g(b,a%b)or a
SP3000

@ Sp3000 ขอบคุณ! ฉันเพิ่งแก้ปัญหาแบบเรียกซ้ำ แต่ก็ยังดีกว่าสิ่งที่ฉันมี
Morgan Thrapp

ไม่อนุญาตให้ใช้ built-in สำหรับ GCD และ LCM ดังนั้นโซลูชันที่สองจะไม่ถูกต้อง
mbomb007

6

MATL , 11 9 ไบต์

ดูเหมือนว่าจะไม่มีใครใช้กำลังดุร้ายจนถึงตอนนี้เลย

ts:\a~f0)

อินพุตเป็นอาร์เรย์คอลัมน์ที่มีตัวเลขสองตัว (ใช้;เป็นตัวคั่น)

ลองออนไลน์! หรือตรวจสอบกรณีทดสอบทั้งหมด

คำอธิบาย

t     % Take input [a;b] implicitly. Duplicate
s     % Sum. Gives a+b
:     % Array [1,2,...,a+b]
\     % Modulo operation with broadcast. Gives a 2×(a+b) array
a~    % 1×(a+b) array that contains true if the two modulo operations gave 0
f0)   % Index of last true value. Implicitly display

5

C, 38 ไบต์

g(x,y){while(x^=y^=x^=y%=x);return y;}

1
คุณต้องรวมคำจำกัดความของฟังก์ชั่นใน bytecount ของคุณ
Rɪᴋᴇʀ

1
@Riker ขอโทษสำหรับสิ่งนั้นฉันเพิ่มคำจำกัดความและอัปเดตการนับ
วิธีที่ Chen

คุณสามารถบันทึกไบต์ที่สองโดยการตั้งชื่อฟังก์ชั่นเพียงแทนg gcd
Steadybox

@Steadybox ตกลงใช่ครั้งแรกที่เข้าร่วมชุมชนนี้ :)
วิธีที่ Chen

1
ยินดีต้อนรับสู่ PPCG!
Rɪᴋᴇʀ

4

C, 28 ไบต์

ฟังก์ชั่นที่ค่อนข้างตรงไปตรงมาใช้อัลกอริทึมของ Euclid บางทีอาจสั้นลงได้โดยใช้อัลกอริธึมสำรอง

g(a,b){return b?g(b,a%b):a;}

ถ้าใครเขียนเสื้อคลุมหลักเล็กน้อย

int main(int argc, char **argv)
{
  printf("gcd(%d, %d) = %d\n", atoi(argv[1]), atoi(argv[2]), g(atoi(argv[1]), atoi(argv[2])));
}

จากนั้นหนึ่งสามารถทดสอบค่าไม่กี่:

$ ./gcd 6 21
gcd (6, 21) = 3
$ ./gcd 21 6
gcd (21, 6) = 3
$ ./gcd 6 8
gcd (6, 8) = 2
$ ./gcd 1 1
gcd (1, 1) = 1
$ ./gcd 6 16
gcd (6, 16) = 2
$ ./gcd 27 244
gcd (27, 244) = 1

4

เขาวงกต 18 ไบต์

?}
:
)"%{!
( =
}:{

สิ้นสุดด้วยข้อผิดพลาด แต่ข้อความแสดงข้อผิดพลาดไปที่ STDERR

ลองออนไลน์!

มันยังรู้สึกไม่ค่อยดีนัก แต่ฉันไม่เห็นวิธีที่จะบีบลูปต่ำกว่า 3x3 ณ จุดนี้

คำอธิบาย

สิ่งนี้ใช้อัลกอริทึมแบบยุคลิด

อันดับแรกมีบิตเป็นเส้นตรงเพื่ออ่านอินพุตและเข้าสู่ลูปหลัก ตัวชี้คำแนะนำ (IP) เริ่มต้นที่มุมซ้ายบนไปทางทิศตะวันออก

?    Read first integer from STDIN and push onto main stack.
}    Move the integer over to the auxiliary stack.
     The IP now hits a dead end so it turns around.
?    Read the second integer.
     The IP hits a corner and follows the bend, so it goes south.
:    Duplicate the second integer.
)    Increment.
     The IP is now at a junction. The top of the stack is guaranteed to be
     positive, so the IP turns left, to go east.
"    No-op.
%    Modulo. Since `n % (n+1) == n`, we end up with the second input on the stack.

ตอนนี้เราเข้าสู่ห่วงของ while-do ซึ่งคำนวณอัลกอริธึมแบบยุคลิด ท็อปส์ซูของสแต็คมีaและb(ด้านบนของจำนวนศูนย์โดยปริยาย แต่เราไม่ต้องการมัน) เราจะเป็นตัวแทนของสแต็คจากด้านหนึ่งไปสู่อีกด้านหนึ่ง

    Main     Auxiliary
[ ... 0 a  |  b 0 ... ]

การวนซ้ำยุติลงครั้งเดียวaคือศูนย์ วนซ้ำทำงานดังนี้:

=    Swap a and b.           [ ... 0 b  |  a 0 ... ]
{    Pull a from aux.        [ ... 0 b a  |  0 ... ]
:    Duplicate.              [ ... 0 b a a  |  0 ... ]
}    Move a to aux.          [ ... 0 b a  |  a 0 ... ]
()   Increment, decrement, together a no-op.
%    Modulo.                 [ ... 0 (b%a)  |  a 0 ... ]

คุณสามารถมองเห็นเราได้แทนที่aและbมีb%aและaตามลำดับ

ในที่สุดเมื่อb%aเป็นศูนย์ IP จะเคลื่อนที่ไปทางตะวันออกและดำเนินการ:

{    Pull the non-zero value, i.e. the GCD, over from aux.
!    Print it.
     The IP hits a dead end and turns around.
{    Pull a zero from aux.
%    Attempt modulo. This fails due to division by 0 and the program terminates.

4

Julia, 21 15 ไบต์

a\b=a>0?b%a\a:b

การใช้งานแบบเรียกซ้ำของอัลกอริทึมแบบยุคลิด ลองออนไลน์!

หากไม่ได้ถูกห้ามใช้งานบิวด์อินgcd(3 ไบต์ในตัว GCD) จะได้คะแนนที่ดีกว่า

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

a\b=             Redefine the binary operator \ as follows:
    a>0?     :       If a > 0:
        b%a\a        Resursively apply \ to b%a and a. Return the result.
              b      Else, return b.

4

Cubix , 10 12ไบต์

?v%uII/;O@

ลองที่นี่

สิ่งนี้ล้อมรอบลูกบาศก์ดังต่อไปนี้:

    ? v
    % u
I I / ; O @ . .
. . . . . . . .
    . .
    . .

ใช้วิธีการแบบยุคลิด

IIตัวเลขสองตัวจะถูกจับจาก STDIN และวางลงบนสแต็ก
/โฟลว์ที่จะส่งสัญญาณ
%Mod the Top of Stack ส่วนที่เหลืออยู่ด้านบนของสแต็ค
?ถ้า TOS 0 แล้วดำเนินการต่อมิฉะนั้นเลี้ยวขวา
vถ้าไม่ใช่ 0 จากนั้นเปลี่ยนทิศทางแล้วuเลี้ยวขวาสองครั้งที่กลับสู่ mod
/ถ้า 0 ไปรอบลูกบาศก์เพื่อ
;ปล่อย TOS TOS Oเอาท์พุท TOS และ@สิ้นสุด


ฉันเพิ่งเขียนคำตอบ Cubix ขนาด 12 ไบต์จากนั้นเริ่มเลื่อนดูคำตอบเพื่อดูว่าฉันต้องจัดการกับทั้งคู่0,xหรือไม่x,0แล้วฉันก็เจอสิ่งนี้ ทำได้ดีนี่!
ETHproductions


3

Windows Batch ขนาด 76 ไบต์

ฟังก์ชั่นวนซ้ำ เรียกว่าชอบด้วยชื่อไฟล์GCD a bgcd

:g
if %2 equ 0 (set f=%1
goto d)
set/a r=%1 %% %2
call :g %2 %r%
:d
echo %f%

3

MATL, 7 ไบต์

pG1$Zm/

ลองออนไลน์!

คำอธิบาย

เนื่องจากเราไม่สามารถอย่างชัดเจนใช้ฟังก์ชั่นในตัว GCD ( Zdใน MATL) ผมได้ใช้ประโยชน์ความจริงที่ว่าตัวคูณร่วมน้อยของaและbครั้งตัวหารร่วมที่ยิ่งใหญ่ที่สุดของaและbมีค่าเท่ากับสินค้าของและab

p       % Grab the input implicitly and multiply the two elements
G       % Grab the input again, explicitly this time
1$Zm    % Compute the least-common multiple
/       % Divide the two to get the greatest common denominator

คุณสามารถบันทึกหนึ่งไบต์ด้วยอินพุตแยกกันสองรายการ:*1MZm/
Luis Mendo

3

แร็กเก็ต (Scheme) 44 ไบต์

การใช้ Euclid ใน Racket (Scheme)

(define(g a b)(if(= 0 b)a(g b(modulo a b))))

แก้ไข: ไม่เห็นโซลูชันของ @Numeri lol อย่างใดก็ตามเราได้รับรหัสเดียวกันอย่างอิสระ


สิ่งนี้ใช้ได้ทั้งสองอย่างหรือไม่?
NoOneIsHere

@NoOneIsHere ใช่มันทำงานได้ทั้งใน
kronicmage

3

> <> , 32 ไบต์

::{::}@(?\=?v{:}-
.!09}}${{/;n/>

ยอมรับค่าสองค่าจากสแต็กและใช้อัลกอริทึม euclidian เพื่อสร้าง GCD

คุณสามารถลองได้ที่นี่ !

สำหรับคำตอบที่ดียิ่งขึ้นใน> <> ลองดูSok's !


1
ฉันพบภาษาใหม่วันนี้ :)
nsane



2

Delphi 7, 148

ฉันคิดว่าฉันพบภาษาที่เลวร้ายที่สุดสำหรับการเล่นกอล์ฟ

unit a;interface function g(a,b:integer):integer;implementation function g(a,b:integer):integer;begin if b=0then g:=a else g:=g(b,a mod b);end;end.

โอ้ผมไม่ทราบว่าสอดสวยดีสำหรับการเล่นกอล์ฟ
MickyT

2

ฮุน 20 ไบต์

|=
{@ @}
d:(egcd +<)

-

Hoon # 2, 39 ไบต์

|=
{a/@ b/@}
?~
b
a
$(a b, b (mod a b))

น่าแปลกที่การใช้งานเพียงอย่างเดียวใน stdlib ของ Hoon สำหรับ GCD นั้นเป็นสิ่งที่ใช้สำหรับ RSA crypto ซึ่งจะส่งกลับค่าอื่น ๆ ฉันต้องห่อมันในฟังก์ชั่นที่ใช้เฉพาะdจากเอาต์พุต

การใช้งานอื่น ๆ เป็นเพียงนิยามของ GCD แบบเรียกซ้ำ


2

Python 3.5, 70 82 73 ไบต์:

lambda*a:max([i for i in range(1,max(*a)+1)if not sum(g%i for g in[*a])])

notในกรณีนี้จะให้แน่ใจว่าผลรวมตัวเลขทั้งหมดใน*argsแบบโมดูโลiเป็นศูนย์

นอกจากนี้ตอนนี้ฟังก์ชั่นแลมบ์ดาสามารถรับค่าได้มากเท่าที่คุณต้องการตราบใดที่จำนวนของค่า>=2ต่างจากgcdฟังก์ชั่นของโมดูลคณิตศาสตร์ ตัวอย่างเช่นอาจใช้ค่า2,4,6,8,10และส่งคืน GCD ที่ถูกต้องเป็น 2


1
คุณถูกจับกุมสำหรับชื่อตัวแปรหลายช่อง (หรือฟังก์ชั่นการโต้แย้ง แต่อย่างใด)
CalculatorFeline

2

Ruby, 23 ไบต์

g=->a,b{b>0?a:g[b,a%b]}

จำไว้ว่าบล็อก ruby ​​นั้นถูกเรียกด้วย g [... ] หรือ g.call (... ) แทนที่จะเป็น g (... )

สินเชื่อบางส่วนเป็นโมฆะ


2
แทนการที่คุณสามารถใช้g.call(a,b) g[a,b]แทนที่จะคุณสามารถใช้proc{|a,b| ->a,b{
ผิดพลาด

1
คุณสามารถบันทึกหนึ่งไบต์โดยใช้b>0แทนb<=0และสลับลำดับของตัวถูกดำเนินการอื่น
ผิดพลาด

2

รหัสเครื่อง ARM, 12 ไบต์:

ประกอบ:

gcd: cmp r0, r1
     sublt r0, r0, r1
     bne gcd

ไม่สามารถรวบรวมสิ่งนี้ได้ในขณะนี้ แต่คำสั่งใน ARM จะใช้เวลา 4 ไบต์ อาจเป็นไปได้ที่จะเล่นกอล์ฟโดยใช้โหมด THUMB-2


เป็นคนที่ดีมาก ๆ ที่ทำงานแบบนี้ในรหัสเครื่อง
Mike Shlanta

นี่ดูเหมือนจะเป็นความพยายามของอัลโกของ Euclid โดยใช้การลบเพียงอย่างเดียวแต่ฉันไม่คิดว่ามันจะใช้งานได้ ถ้าเป็นเช่นr0 > r1นั้นก็subltจะไม่ทำอะไรเลย (เพรดิเคตltเป็นเท็จ) และbneจะเป็นการวนซ้ำไม่สิ้นสุด ฉันคิดว่าคุณต้องสลับถ้าไม่ltดังนั้นวงเดียวกันสามารถทำได้b-=aหรือa-=bตามความจำเป็น หรือลบล้างถ้าย่อยผลิตพกพา (aka ยืม)
Peter Cordes

คู่มือชุดคำสั่ง ARMนี้ใช้อัลกอริทึมการลบ GCD เป็นตัวอย่างสำหรับการคาดการณ์ล่วงหน้า (หน้า 25) พวกเขาใช้cmp r0, r1/ subgt r0, r0, r1/ /sublt r1, r1, r0 bne gcdนั่นคือคำสั่ง 16B ใน ARM หรืออาจเป็น 12 คำสั่งใน thumb2?
Peter Cordes

1
บน x86 ฉันจัดการ 9 sub ecx, eaxไบต์ด้วย: jae .no_swap/ add ecx,eax/ xchg ecx,eax/ jne/ ดังนั้นแทนที่จะเป็น cmp ฉันเพิ่งจะย่อยแล้วเลิกทำและสลับถ้าสิ่งที่ควรจะไปทางอื่น ฉันทดสอบสิ่งนี้และใช้งานได้ ( addจะไม่jneออกในเวลาที่ไม่ถูกต้องเพราะมันไม่สามารถสร้างศูนย์ได้เว้นแต่ว่าหนึ่งในอินพุตนั้นเป็นศูนย์ที่จะเริ่มต้นด้วยและเราไม่สนับสนุนสิ่งนั้นอัปเดต: เราจำเป็นต้องสนับสนุนทั้งอินพุตเป็นศูนย์: /)
Peter Cordes

สำหรับ Thumb2 นั้นมีiteคำสั่ง: if-then-else ควรเหมาะสำหรับ cmp / sub ทางเดียว / sub ในทางอื่น
Peter Cordes

2

TI-Basic, 10 ไบต์

Prompt A,B:gcd(A,B

การไม่แข่งขันเนื่องจากกฎใหม่ห้ามใช้ gcd บิวด์อิน


โซลูชั่น17 ไบต์แบบไม่มีgcd(ในตัว

Prompt A,B:abs(AB)/lcm(A,B

การไม่แข่งขันเนื่องจากกฎใหม่ห้ามใช้ lcm ในตัว


โซลูชัน27 ไบต์ที่ไม่มีgcd(หรือlcm(มีในตัว:

Prompt A,B:While B:B→T:BfPart(A/B→B:T→A:End:A

โซลูชันแบบเรียกซ้ำ35 ไบต์โดยไม่มีgcd(หรือlcm(มีในตัว (ต้องใช้ระบบปฏิบัติการ 2.53 MP หรือสูงกว่าต้องตั้งชื่อ prgmG ):

If Ans(2:Then:{Ans(2),remainder(Ans(1),Ans(2:prgmG:Else:Disp Ans(1:End

คุณจะผ่านการขัดแย้งกับตัวแปร recursive เป็น{A,B}ดังนั้นสำหรับตัวอย่างเช่นจะให้ผลผลิต{1071, 462}:prgmG21


สีที่ฉันประทับใจ
Mike Shlanta

prgmGคุณอาจจะพูดถึงว่าสุดท้ายจะต้องบันทึกเป็น
ปาเก็ตตี้

2

05AB1E , 10 ไบต์

รหัส:

EàF¹N%O>iN

ลองออนไลน์!


ด้วยบิวด์อิน:

¿

คำอธิบาย:

¿   # Implicit input, computes the greatest common divisor.
    # Input can be in the form a \n b, which computes gcd(a, b)
    # Input can also be a list in the form [a, b, c, ...], which computes the gcd of
      multiple numbers.

ลองออนไลน์! หรือลองกับหลายหมายเลข


2

Oracle SQL 11.2, 104 118 ไบต์

SELECT MAX(:1+:2-LEVEL+1)FROM DUAL WHERE(MOD(:1,:1+:2-LEVEL+1)+MOD(:2,:1+:2-LEVEL+1))*:1*:2=0 CONNECT BY LEVEL<=:1+:2;

แก้ไขสำหรับอินพุต 0


ทำงานไม่ถูกต้องหากอินพุตใดอินพุตหนึ่งเป็นศูนย์
Egor Skriptunoff

สิ่งนี้จะช่วยคุณได้ไม่กี่SELECT MAX(LEVEL)FROM DUAL WHERE MOD(:1,LEVEL)+MOD(:2,LEVEL)=0 CONNECT BY LEVEL<=:1+:2;
MickyT

2

> <> , 12 + 3 = 15 ไบต์

:?!\:}%
;n~/

คาดว่าหมายเลขอินพุตจะแสดงบนสแต็กดังนั้น +3 ไบต์สำหรับ-vแฟล็ก ลองออนไลน์!

การใช้อัลกอริทึมแบบยุคลิดอีกอันหนึ่ง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.