เป็นไปได้ไหมที่จะทำให้รหัส C นี้เล็กลง? มันพิมพ์จำนวนเฉพาะจาก 0 ถึง 1,000
C, 89 ตัวอักษร
int i,p,c;for(i=2;i<1e3;i++){c=0;for(p=2;p<i;p++)if(i%p==0)c++;if(c==0)printf("%u\n",i);}
เป็นไปได้ไหมที่จะทำให้รหัส C นี้เล็กลง? มันพิมพ์จำนวนเฉพาะจาก 0 ถึง 1,000
C, 89 ตัวอักษร
int i,p,c;for(i=2;i<1e3;i++){c=0;for(p=2;p<i;p++)if(i%p==0)c++;if(c==0)printf("%u\n",i);}
คำตอบ:
59 57 ไบต์
ขึ้นอยู่กับวิธีการแก้ปัญหา @feersum แต่การตรวจสอบเบื้องต้นสามารถตีเพิ่มเติม
for(int p=1,d;d=p++%999;d||printf("%d\n",p))for(;p%d--;);
แก้ไขตามความเห็นของ Runer112
d=p++%999
. ไม่งั้นนี่มันดูเป็นงานตีกอล์ฟที่แน่นหนา!
ใน C ไม่มีทางเลือกอื่นสำหรับแผนกทดลอง แต่สามารถตีกอล์ฟได้เล็กน้อย
for(int p=1,d;p++<999;d&&printf("%d\n",p))for(d=p;--d>1;)d=p%d?d:1;
ต้องการการประกาศเริ่มต้น C99 ซึ่งบันทึกได้ 1 ไบต์
(ฉันเขียนสิ่งนี้โดยไม่ตระหนักถึงข้อ จำกัด ด้านขนาดของจำนวนเต็มใน C ดังนั้นจึงไม่มีประโยชน์ที่จะทำให้รหัสสั้นลง)
ก่อนคำเกี่ยวกับอัลกอริทึม ก่อนตีกอล์ฟรหัสของคุณคุณควรคิดถึงกลยุทธ์โดยรวมที่ดีที่สุดเพื่อให้ได้ผลลัพธ์
คุณกำลังตรวจสอบ primality โดยการทำส่วนการพิจารณาคดี - การทดสอบแต่ละตัวหารที่มีศักยภาพของp
i
นั่นเป็นค่าใช้จ่ายเป็นตัวละครเพราะมันใช้เวลาสองลูป ดังนั้นการทดสอบแบบดั้งเดิมโดยไม่มีลูปจึงมีแนวโน้มที่จะบันทึกอักขระ
วิธีที่สั้นกว่ามักจะใช้ทฤษฎีบทของวิลสัน : จำนวนn
นั้นเป็นจำนวนเฉพาะถ้าหากว่า
fact(n-1)%n == n-1
ซึ่งfact
เป็นฟังก์ชั่นแฟกทอ เนื่องจากคุณกำลังทดสอบความเป็นไปได้ทั้งหมดn
ตั้งแต่1
ถึงจนถึง1000
เป็นเรื่องง่ายที่จะหลีกเลี่ยงการใช้แฟกทอเรียลโดยการติดตามผลิตภัณฑ์ที่กำลังทำงานอยู่P
และอัปเดตโดยP*=n
หลังจากแต่ละลูป นี่คือการใช้งาน Python ของกลยุทธ์นี้เพื่อพิมพ์จำนวนมากถึงล้านครั้ง
หรือความจริงที่ว่าโปรแกรมของคุณจะต้องมีสิทธิ์มากถึง 1,000 รายการเท่านั้นที่เปิดใช้กลยุทธ์อื่น: การทดสอบแบบดั้งเดิมของแฟร์มาต์ สำหรับบางคนa
ทุกคนn
พึงพอใจ
pow(a,n-1)%n == 1
แต่น่าเสียดายที่บางคอมโพสิตยังผ่านการทดสอบนี้สำหรับบางคนn
a
เหล่านี้เรียกว่าpseudoprimes แฟร์มาต์ แต่a=2
และa=3
ไม่ล้มเหลวด้วยกันจนกว่าn=1105
พวกเขาจะพอเพียงเพื่อจุดประสงค์ของคุณในการตรวจสอบเฉพาะช่วงเวลาจนถึง 1,000 (ถ้า 1,000 เป็น 100 แทนที่จะเป็นคุณจะสามารถใช้งานได้เท่านั้นa=2
) ดังนั้นเราจึงตรวจสอบขั้นแรกด้วย (ungolfed code)
pow(2,n-1)%n == 1 and pow(3,n-1)%n == 1
สิ่งนี้ก็ล้มเหลวในการรับรู้เฉพาะช่วงที่ 2 และ 3 ดังนั้นสิ่งเหล่านั้นจำเป็นต้องได้รับการดูแลเป็นพิเศษ
วิธีการเหล่านี้สั้นลงหรือไม่? ฉันไม่ทราบเพราะฉันไม่ได้เขียนโค้ดใน C. แต่พวกเขาเป็นแนวคิดที่คุณควรลองก่อนที่คุณจะตกลงบนชิ้นส่วนของรหัสเพื่อเริ่ม eking out ตัวอักษร
int
s เป็น 32 บิต กันไปสำหรับแฟร์มาต์
fact(int n, int m) { return (n==0) ? 1 : (n*f(n-1)) % m; }
แล้วผลจะไม่ท่วมจำนวนเต็ม 32 n
บิตสำหรับค่าแม้จะมีขนาดใหญ่พอสมควร ( m
เป็นโมดูลัส)
(n*fact(n-1,m)) % m
ฉันคิดว่าคุณหมายถึง ซึ่งเน้นปัญหา: คุณไม่สามารถหลีกเลี่ยงการเรียกซ้ำในการดำเนินการfact
เพราะm
จะแตกต่างกันสำหรับการวนซ้ำของลูปด้านนอกแต่ละครั้ง
(เพียงใช้เทคนิคบางอย่างที่เรียนรู้ในภาษาอื่น)
int i=0,p,c;for(;i<1e3;i++){c=0;for(p=2;p<i;)c+=i%p++<1;c||printf("%u\n",i);}
for(int i=0,p,c;i<1e3;i++){c=0;for(p=2;p<i;)c+=i%p++<1;c||printf("%u\n",i);}
การนำคำตอบของฉันไปใช้กับคำถามที่คล้ายกันอีกครั้ง
แก้ไข : ชิ้นส่วนรหัสสแตนด์อะโลนไม่มีฟังก์ชั่นที่จะโทร
for(int m,n=2;n<999;m>1?m=n%m--?m:n++:printf("%d\n",m=n));
โปรแกรมที่สมบูรณ์:
n=2;main(m){n<999&&main(m<2?printf("%d\n",n),n:n%m?m-1:n++);}
แรงบันดาลใจจากโซลูชันของ Alchymist:
int i=1,p;for(;i++<1e3;p-i||printf("%d\n",i)){p=1;while(i%++p);}