แสดงรายการของจำนวนตรรกยะทั้งหมด


13

จากคณิตศาสตร์ทั้งหมดจะมีทฤษฎีไม่กี่ข้อที่เกินกว่าสามัญสำนึกทั้งหมด หนึ่งในนั้นคือความจริงที่ว่ามีขนาดแตกต่างกันไป อีกข้อเท็จจริงที่น่าสนใจคือความคิดที่ว่าอินฟินิตี้จำนวนมากซึ่งดูเหมือนจะมีขนาดแตกต่างกันนั้นมีขนาดเท่ากัน มีจำนวนเท่าจำนวนเต็มเป็นจำนวนเต็มเนื่องจากมีจำนวนตรรกยะ

แนวคิดทั่วไปของคำถามนี้คือการเผชิญหน้ากับความเป็นจริงที่แปลกประหลาดของอินฟินิตี้ ในการท้าทายนี้โปรแกรมของคุณจะแสดงรายการซึ่งจะ:

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

ความท้าทาย

ความท้าทายของคุณคือการเขียนโปรแกรมที่สั้นที่สุดที่จะส่งออกรายการพิเศษด้วยกฎต่อไปนี้:

  1. รายการทั้งหมดที่มีดัชนีซึ่งไม่ใช่ตัวเลขจตุรัสควรถูกตั้งค่าเป็นศูนย์ ดังนั้นรายการแรกจะไม่ใช่ศูนย์ที่สองและสามจะเป็นศูนย์ส่วนที่สี่จะไม่ใช่ศูนย์ ฯลฯ
  2. ตัวเลขที่มีเหตุผลทั้งหมดจะอยู่ในรูปของเศษส่วนที่ไม่เหมาะสม (เช่น 4/5 หรือ 144/13) ที่ได้รับการทำให้เข้าใจง่าย 0ยกเว้นเป็นศูนย์ซึ่งจะเป็นเพียงแค่
  3. ตัวเลขเหตุผล (บวกและลบ) ทั้งหมดควรปรากฏในรายการในที่สุดหากโปรแกรมของคุณทำงานนานพอและมีหน่วยความจำเพียงพอ สำหรับจำนวนตรรกยะโดยเฉพาะเวลาที่ต้องใช้อาจมีขนาดใหญ่โดยพลการ แต่จะ จำกัด เวลาเสมอ
  4. ถ้าวิ่งตามเวลาที่ไม่ จำกัด จำนวนไม่ควรมีจำนวนตรรกยะที่ไม่เป็นศูนย์สองเท่า

กฎข้อที่ 3 อนุญาตให้มีการเปลี่ยนแปลงบางอย่างเนื่องจากมีจำนวนไม่ จำกัด ทางกฎหมายที่เป็นไปได้ที่แตกต่างกัน

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

ตัวอย่างตัวอย่างของการส่งออก:

1: 1/1
2: 0
3: 0
4: 2/1
5: 0
6: 0
7: 0
8: 0
9: -2/1
10: 0
etc...

กฎระเบียบและบันทึก

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

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


1
กฎข้อ 1 คืออะไร? คุณแค่ต้องการให้คนเล่นกอล์ฟสองรายการแยกกันเพื่อทดสอบความเป็นอันดับหนึ่งและระบุเหตุผลหรือไม่?
Peter Taylor

มันแสดงให้เห็นว่าส่วนเล็ก ๆ ของจำนวนเต็มยังคงมี cardinality เช่นเดียวกับชุดของตัวเลขที่มีเหตุผลเต็มรูปแบบและยังช่วยให้เปอร์เซ็นต์ของช่องว่างที่จะเข้าใกล้ (แต่ไม่ถึง) 100%
PhiNotPi

ฉันสมมติว่าโปรแกรมจำเป็นต้องทำงานในหน่วยความจำคงที่เช่นกันคือมันไม่สามารถสันนิษฐานได้ว่าเครื่องสามารถจัดสรรได้มากขึ้นหรือไม่ นอกจากนี้ยังเป็นการขัดกับกฎที่ใช้ (พูด) C int สำหรับดัชนีรายการเมื่อคุณรู้ว่ามันมีช่วง จำกัด ? (แม้ว่าขีด จำกัด ที่แน่นอนอาจแตกต่างกันไปตามการนำไปใช้) จำเป็นต้องมีรูปแบบของบิกนัมบ้างไหม?
breadbox

1
@PhiNotPi มีวิธีที่ง่ายกว่ามากในการทำเช่นนั้นและมันเป็นสิ่งที่ทำให้ไขว้เขวจากส่วนที่น่าสนใจของคำถาม
Peter Taylor

1
โปรดทราบว่า1: 0จะเป็นบรรทัดแรกของเอาต์พุต - สิ่งนี้ขัดกับตัวอย่างของคุณและก็ไม่สมเหตุสมผลสำหรับฉัน
Wrzlprmft

คำตอบ:


6

Haskell, 184 ตัวอักษร

main=putStr.unlines$zip[1..](s>>=g)>>=h
s=(1,1):(s>>=f)
f(a,b)=[(a,a+b),(a+b,b)]
g x@(a,b)=[x,(-a,b)]
h(i,(a,b))=(i^2)%(u a++'/':u b):map(%"0")[i^2+1..i*(i+2)]
i%s=u i++": "++s
u=show

นี่เป็นการสำรวจเส้นทางที่กว้างเป็นอันดับแรกของต้นไม้ Calkin-Wilfซึ่งให้ผลเป็นตัวเลขเชิงบวกทั้งหมดในรูปแบบที่ลดลงเพียงครั้งเดียว จากนั้นสลับระหว่างค่าบวกและลบเพื่อให้ครอบคลุมจำนวนตรรกยะที่ไม่เป็นศูนย์และแผ่นอิเล็กโทรดด้วยค่าศูนย์ระหว่างรายการตาราง

เอาท์พุท (ไม่รวมเส้นศูนย์สำหรับความกะทัดรัด):

1: 1/1
4: -1/1
9: 1/2
16: -1/2
25: 2/1
36: -2/1
49: 1/3
64: -1/3
81: 3/2
100: -3/2
...

5

Sage, 103 113 128

ปราชญ์สามารถแสดงรายการปันส่วนได้อย่างง่ายดาย! การจัดรูปแบบให้เหมาะสมกับความต้องการของโปรแกรมเช่นเคยทำลายทุกอย่าง

for i,q in enumerate(QQ):
 for j in[(i-1)^2+1..i*i]:print'%d:'%j,[0,'%d/%d'%(q.numer(),q.denom())][j==i*i]

Sage ระบุQQตามความสูงของพวกเขา: ค่าสัมบูรณ์สูงสุดของตัวเศษและตัวหารหลังจากการลด GCD


คุณสามารถกำจัดx.next()และใช้printเพียงครั้งเดียวดังต่อไปนี้นำคะแนนลงไปที่ x=enumerate(QQ) for i,q in x: for j in[(i-1)^2+1..i*i]: print'%d: '%j,'%d/%d'%(q.numer(),q.denom())if j.is_square()else 0124: สิ่งนี้ไม่แสดงอย่างถูกต้องในความคิดเห็น แต่ฉันคิดว่าคุณสามารถเห็นสิ่งที่ฉันหมายถึง
res

BTW ฉันสังเกตเห็นว่าหลังจากองค์ประกอบ 4 ประการแรกการแจงนับของ Sage ไม่เหมือนกับในคำตอบอื่น ๆ สูตร Calkin-Wilf ให้ลำดับที่ตัวส่วนของเหตุผลคือเศษของเหตุผลต่อไป; เช่น (... , 1/3, 3/2, 2/3, ... ) เมื่อเปรียบเทียบกับ Sage (... , 1/3, 3/1, 2/3, ... ) ฉันดูเหมือนจะไม่พบเอกสารใด ๆ สำหรับการแจงนับของ Sage เพื่อดูว่ามันคำนวณอย่างไร
res

@res ขอบคุณ! ฉันต้องการรวมคำแถลงการพิมพ์ แต่ลืมใช้เครื่องหมาย [x..y] ดีใจที่ได้เห็นผู้ใช้ Sage คนอื่นที่นี่!
บูธ


2

Haskell, 55 ไบต์

mapM_ print$join$iterate(>>=(\x->[x+1,1/(1+1/x)]))[1%1]

เอาท์พุท

1 % 1
2 % 1
1 % 2
3 % 1
2 % 3
3 % 2
1 % 3
4 % 1
...

1% 1 เป็นรากของต้นไม้ Calkin-Wilf การวนซ้ำเพิ่มทั้งสองลูกของแต่ละโหนด การเข้าร่วมยุบระดับลงในรายการเดียว

120 ตัวอักษรหากคุณเพิ่มการนำเข้าที่เหมาะสม 0 และเชิงลบ:

import Data.Ratio
import Control.Monad
main=mapM_ print$0:(join(iterate(>>=(\x->[x+1,1/(1+1/x)]))[1%1])>>=(\x->[-x,x]))

เอาท์พุท

0 % 1
(-1) % 1
1 % 1
(-2) % 1
2 % 1
(-1) % 2
1 % 2
(-3) % 1
3 % 1
(-2) % 3
2 % 3
(-3) % 2
3 % 2
(-1) % 3
1 % 3
(-4) % 1
4 % 1
...

แสดงผลช่องว่างเปล่า? ที่อยู่ในรสนิยมไม่ดี :( คุณมีฉันที่ "รายชื่อของปันส่วนบวกทั้งหมด"


mapM_ print$fix((1%1:).(>>= \x->[x+1,1/(x+1)]))คือ 47 ตัวอักษร จากhaskellwiki ทำงานตามที่เป็นอยู่โดยไม่มีการนำเข้าใด ๆ ที่haskell.orgของ "ลองมัน" REPL (ดีไม่มีmapM_ printส่วน ... )
Will Ness

1

PHP 105 ไบต์

หมายเหตุ: รหัสนี้จะต้องบันทึกเป็น iso-8859-1 (ansi) เพื่อให้ทำงานได้อย่างถูกต้อง ตัวแปลออนไลน์ที่เข้ารหัสอินพุตทั้งหมดเป็น utf8 โดยค่าเริ่มต้น (เช่น ideone) จะสร้างเอาต์พุตที่ไม่ถูกต้อง

<?for($f=µ;$i++<$j*$j||++$j%2||(--$$f?$$f--:$f^=C);)echo"$i: ",$i==$j*$j?$j%2?$x=++$ö.~Ð.++$µ:"-$x":0,~õ;

ใช้การแจงนับของ Georg Cantor (แก้ไขเล็กน้อยสำหรับ +/- ค่า)

หากคุณมีปัญหาในการเรียกใช้รหัสข้างต้น (น่าจะเกิดจากข้อความสังเกตมากเกินไป) ให้ใช้สิ่งนี้แทน (107 ไบต์):

<?for($f=µ;$i++<$j*$j||++$j%2||(--$$f?$$f--:$f^=C);)echo"$i: ",$i==$j*$j?$j%2?$x=++$ö.'/'.++$µ:"-$x":0,'
';

1
ฉันพบข้อผิดพลาดรันไทม์ด้วยรหัสนี้ (ซึ่งดูเหมือนว่าจะมีอักขระแปลก ๆ เช่น "$ ö. ~ Ð.")
res

คุณสามารถแสดงให้เห็นว่าวิธีนี้ใช้งานได้ดีหรือไม่? ฉันได้รับข้อผิดพลาดเช่นกัน: ideone.com/ru1fo
mellamokb

Ideone ดูเหมือนว่าจะเกิดข้อผิดพลาดเมื่อมีการสร้างข้อความประกาศมากเกินไป : ทั้ง ~ Ð (เท่ากับ '/') และ ~ õ (เท่ากับ "\ n") จะสร้างการแจ้งเตือนทุกการวนซ้ำ แน่นอนถ้าคุณปิดประกาศมันไม่ได้เป็นปัญหา วางที่มีทั้งแทนที่ (107 Bytes): ideone.com/lFUbl
primo

ฉันเพิ่งสังเกตเห็นว่าตัวแปล PHP ของ Ideone สร้างผลลัพธ์ผิด หากคุณเรียกใช้รหัสในเครื่องคุณจะเห็นว่าถูกต้อง หรือคุณสามารถทดสอบด้วย interpretter PHP ที่ถูกต้องเช่นการตรวจสอบประสิทธิภาพการทำงานของความโกลาหลกอล์ฟ: golf.shinh.org/checker.html (บันทึกเป็นไฟล์และอัพโหลด)
พรีโม่

เมื่อฉันบันทึกรหัสที่แก้ไขของคุณไปยังไฟล์ที่มีการเข้ารหัส ANSI มันจะทำงานบนล่าม Anarchy Golf อย่างไรก็ตามขณะนี้มีปัญหาที่แตกต่าง: ละเมิดข้อกำหนดที่ว่า"ไม่มีจำนวนตรรกยะที่ไม่เป็นศูนย์จะปรากฏเป็นสองเท่า"ในรายการ ในความเป็นจริงรหัสปรากฏขึ้นเพื่อแสดงรายการทุก ๆ เหตุผลไม่ จำกัด จำนวนครั้ง; เช่น 1/1, 2/2, 3/3, ... ล้วนเป็นเหตุผลเดียวกันและเช่นเดียวกันสำหรับ 1/2, 2/4, 3/6, ... และอื่น ๆ
res

0

ระดับเสียงคู่, 168 ไบต์

a=b=p=1;do for i=(p-1)^2+1:p^2-1 printf("%d: 0\n",i)end
printf("%d: %d/%d\n",p^2,a,b)
a=-a;if a>0do if b==1 b=a+1;a=1;else a++;b--;end until 1==gcd(a,b)end
p++;until 0

การแก้ปัญหานั้นไม่ซับซ้อนมากนักมันเป็นเพียงแค่เส้นทแยงมุมที่เรียบง่ายของ "พรม" ของตัวเลขที่มีเหตุผลโดยละทิ้งเศษส่วนทั้งหมดที่สามารถทำให้ง่ายขึ้น หลังจากจำนวนบวกa/bมันจะอยู่ตรงข้ามกัน-a/bเสมอก่อนที่จะเรียงจากลำดับถัดไป

การเคลื่อนที่ในแนวทแยงของการปันส่วนบวกทั้งหมด

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

Degolfed:

a=b=p=1
do
    for i=(p-1)^2+1:p^2-1
        printf("%d: 0\n",i)         # p=2,3,4: 1..3,5..8,10..15
    end
    printf("%d: %d/%d\n", p^2,a,b); # p=2,3,4: 4,9,16
    a=-a;
    if a>0                          # the rule is: after a/b, a>0 output -a/b
        do
            if b==1 b=a+1;a=1; else a++;b--; end
        until 1==gcd(a,b)
    end
    p++;
until 0
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.