เปรียบเทียบจำนวนเต็มสองจำนวนใน C หรือ C ++ โดยไม่มีตัวดำเนินการเปรียบเทียบ


13

สร้างโปรแกรมที่สั้นที่สุดซึ่งใช้จำนวนเต็มสองลายเซ็นเป็นอินพุต (ผ่าน stdin หรือเป็นอาร์กิวเมนต์) และแสดง 3 เอาต์พุตที่แตกต่างกันขึ้นอยู่กับว่าหมายเลขแรกคือ (1) มากกว่า (2) เล็กกว่าหรือ (3) เท่ากับวินาที จำนวน.

จับ

คุณไม่สามารถใช้สิ่งต่อไปนี้ในโปรแกรมของคุณ:

  • มาตรฐานผู้ประกอบการเปรียบเทียบ: <, >, <=, >=, ,==!=
  • ไฟล์ไลบรารีใด ๆ ที่นอกเหนือจากconio, หรือstdioiostream
  • อักขระ ASCII ที่ไม่ใช่ ASCII หรือไม่สามารถพิมพ์ได้

ผู้ชนะ

โปรแกรมที่มีจำนวนอักขระสั้นที่สุดเป็นผู้ชนะ


ฉันคิดว่าการใช้สิ่งต่าง ๆabs โดยไม่รวมไฟล์ไลบรารี (เพราะคอมไพเลอร์รู้อยู่แล้ว) ไม่ได้รับอนุญาตเช่นกัน
Martin Ender

1
@ MartinBüttnerใช่ว่าจะเป็นสมมติฐานที่ถูกต้อง :)
grove

5
ทำไมข้อ จำกัด ถึง C (++) หากเป็นเพราะคุณต้องการคำตอบให้พกพาแม้จะไม่สามารถพกพาประเภทพื้นฐานของ C ได้คุณก็ควรระบุไว้ หากเป็นข้อ จำกัด โดยพลการคุณควรทราบว่าข้อ จำกัด โดยพลการของภาษาหนึ่งนั้นไม่เป็นที่นิยมในเว็บไซต์นี้
Peter Taylor

8
@PeterTaylor มันเป็นส่วนหนึ่งของความท้าทาย มันจะเป็น ballgame ที่แตกต่างกันโดยสิ้นเชิงถ้าคำถามเป็นผู้ไม่เชื่อเรื่องภาษา การ จำกัด ให้เป็น C / C ++ จะเปลี่ยนกลยุทธ์ที่ใช้เมื่อใกล้ถึงปัญหา ฉันตระหนักถึงความต้องการคำถามที่จะเปิดให้ภาษาส่วนใหญ่เพื่อส่งเสริมการมีส่วนร่วมของผู้คนมากขึ้น แต่ในปัญหานี้ข้อ จำกัด ของ C / C ++ และผู้ประกอบการและวิธีการเฉพาะของพวกเขาเป็นส่วนหนึ่งของความท้าทาย
grove

1
@EvilTeach ใช่; หากสิ่งใดไม่ได้ถูกห้ามอย่างชัดเจนในคำถามนั้นจะได้รับอนุญาต
grove

คำตอบ:


2

53 ไบต์

main(a,b){scanf("%d%d",&a,&b);printf("%ld",0l+a-b);}

เฉพาะอักขระตัวแรกของเอาต์พุตที่เกี่ยวข้อง เอาต์พุตที่แตกต่างกันสามแบบคือ:

  1. '-' ถ้า b> a
  2. '0' ถ้า a == b
  3. ตัวละครอื่นใดถ้า a> b

มันใช้งานได้กับช่วงอินพุตทั้งหมดของ int บนทุกแพลตฟอร์มที่ sizeof (ยาว)> sizeof (int)

แก้ไข: มีค่าใช้จ่ายอักขระพิเศษหนึ่งตัวเพื่อให้กรณีที่ 3 พิมพ์ '+' โดยไม่ซ้ำกันแทน:

main(a,b){scanf("%d%d",&a,&b);printf("%+ld",0l+a-b);}

6

บางทีฉันอาจจะพลาดกฎบางอย่าง แต่ ...

81 ไบต์

main(a,b){scanf("%d%d",&a,&b);long long l=a;l-=b;printf("%lld%d",--l>>63,l>>63);}

เพื่อถ่ายทอด00ถ้าa > b, -10ถ้าa == bและถ้า-1-1a < b


เช่นเดียวกับรหัสทั่วไปประเภทนี้ C ไม่รับประกันว่าจะทำงานได้ long longอาจมากกว่า 64 บิตintอาจมีขนาดใหญ่ดังนั้นคุณสามารถล้นได้ผลลัพธ์ของการเปลี่ยนค่าลบที่ถูกต้องคือการใช้งาน คำตอบที่ได้มาจาก C ค่อนข้างมากมีปัญหาที่คล้ายกัน
Yann Vernier

1
@YannVernier: เข้าใจ ฉันเดาว่าวิธีแก้ปัญหาที่เข้าใจผิดได้ 100% จะเป็นสัตว์ประหลาดเพราะสิ่งเดียวที่เราทำได้อย่างปลอดภัย (เช่นโดยไม่มีการขยับหรือล้น) คือการกระตุกเล็กน้อยและการทำเช่นนั้นอย่างปลอดภัยเราต้องกำหนดความยาวของตัวถูกดำเนินการโดยใช้sizeof.
COTO

6

90 ไบต์

หากเราสามารถใช้stdioทำไมไม่ใช้ความสามารถในการจัดรูปแบบเพื่อทำการเปรียบเทียบ

main(a,b){scanf("%d%d",&a,&b);snprintf(&a,2,"%d",b-a);a&=63;putchar(51-!(a-45)-!!(a-48));}

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

72 ไบต์

Quotients ถูกปัดเศษเป็นศูนย์ แต่กะขวาคือ (ในทางปฏิบัติ) "ปัดเศษ" นั่นเป็นของแจกที่ตายแล้ว

main(a,b){scanf("%d%d",&a,&b);a-=b;putchar(a?a|=1,a/2-(a>>1)?60:62:61);}

65 79 ไบต์

คุณสมบัติที่แตกต่างอีกประการของจำนวนลบคือพวกมันสร้างโมดูโลลบ อันนี้ไม่ได้ขึ้นอยู่กับการแสดงจำนวนเต็มเลย มันใช้งานได้กับเครื่องปิ้งขนมปัง 8 บิตส่วนเกิน -128 ของฉัน! โอ้และเนื่องจากเราสามารถใช้conioทำไมไม่บันทึกสองไบต์ด้วยputch? ตอนนี้ถ้าฉันสามารถหาสำเนาของ TurboC ของฉันเท่านั้น ...

main(a,b){scanf("%d%d",&a,&b);long long d=a;d-=b;putch(d?d|=1,d%2-1?60:62:61);}

แก้ไข : จับแตกต่างกันมากสมมติว่ามีความกว้างมากกว่าlong longint


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

1
@ มาร์ติน: มันใช้งานได้กับ GCC แต่ฉันไม่แน่ใจว่ามันดีจริงๆ
Ell

สิ่งที่ฉันหมายถึงคือคุณแยกความแตกต่างระหว่างอินพุตa = 1, b = 23และa = 12, b = 3อย่างไร คุณไม่จำเป็นต้องใส่123STDIN ในทั้งสองกรณี?
Martin Ender

1
อย่างที่ฉันพูดมันดูเหมือนว่าจะทำงานได้ (กับ1 23และ12 3เป็นอินพุต)
Ell

2
โอ้คุณมีช่องว่างในอินพุท ใช่ฉันไม่แปลกใจที่ได้ผลจริง
Martin Ender

5

64 61 ตัวอักษร

main(a,b){scanf("%d%d",&a,&b);for(a-=b;a/2;a/=2);putchar(a);}

พิมพ์ค่าอักขระเป็น -1, 0 และ 1 สำหรับน้อยกว่าเท่ากับหรือมากกว่าตามลำดับ

การดำเนินการนี้อาศัยอยู่กับพฤติกรรมที่ไม่ได้กำหนดสำหรับbความเป็นอยู่ของชนิดintและปัจจัยการผลิตนอกช่วงไปINT_MIN / 2 INT_MAX / 2บนแพลตฟอร์มที่ลงนามล้นล้อมรอบไม่ว่าจะเป็น 2s-สมบูรณ์ (พื้นทั้งหมดของพวกเขา) หรือการลงชื่อเข้าใช้ขนาดก็จะล้มเหลว 25% intของคู่ที่เป็นไปได้ของการที่ถูกต้อง ที่น่าสนใจ (สำหรับฉันอยู่แล้ว) มันจะทำงานได้อย่างถูกต้องบนแพลตฟอร์มที่อิ่มตัวล้นลงนาม


สิ่งนี้จะไม่ทำงานหากa-bล้น
Dennis

น่าเศร้าที่เป็นจริง แต่ฉันไม่สามารถนึกถึงแพลตฟอร์มใด ๆ ที่ไม่เชื่อเรื่องพระเจ้าเพื่อหลีกเลี่ยงปัญหานี้โดยไม่ใช้ตัวดำเนินการเปรียบเทียบ คำถามไม่ได้ระบุช่วงของอินพุตที่ผลลัพธ์ต้องถูกต้อง คำตอบนี้รับประกันโดยมาตรฐานการทำงานสำหรับอินพุตทั้งหมดระหว่าง-(2^14)และ2^14 - 1บนแพลตฟอร์มที่สอดคล้องทั้งหมดและมันอาจจะทำงานในช่วงที่กว้างขึ้นอย่างมากบนแพลตฟอร์มส่วนใหญ่ คำตอบอื่น ๆ ทั้งหมด ณ จุดนี้ทำให้สมมติฐานเกี่ยวกับขนาดของประเภทขนาดที่สัมพันธ์กันของประเภทหรือการเป็นตัวแทน
laindir

คำถามที่ว่าจำนวนเต็มสองลายเซ็นเป็นอินพุทดังนั้นฉันจะบอกว่ามันต้องใช้ได้กับทุกคู่ main(a,b)เป็นพฤติกรรมที่ไม่ได้กำหนดไว้ดังนั้นจึงไม่มีคำตอบใดที่รับประกันได้ว่าจะทำงาน ไม่ต้องกังวลกับการพกพา
เดนนิส

คุณพูดถูกเกี่ยวกับพฤติกรรมที่ไม่ได้กำหนดดังนั้นการใช้งานของฉันจึงไม่ได้รับประกันอะไรตามมาตรฐาน ฉันจะเพิ่มบันทึกย่อที่ระบุว่าข้อ จำกัด ของมันคืออะไร
laindir

4

 59    54 ตัวอักษร

นักต้มตุ๋น 54 คนที่มีคอมไพเลอร์อย่าง gcc ซึ่งไม่ได้หยุดอยู่ที่main(x,y):

main(x,y){scanf("%d%d",&x,&y);y-=x;putchar(y>>31|!y);}

อย่างอื่น 59 ตัวอักษร:

main(){int x,y;scanf("%d%d",&x,&y);y-=x;putchar(y>>31|!y);}

เอาท์พุท:

  • รหัส ASCII 0x00 ถ้า x <y
  • รหัส ASCII 0xFF ถ้า x> y
  • รหัส ASCII 0x01 ถ้า x == y

1
ฉันรับรองได้ว่าคุณmain(x,y)ทำงานเป็น gcc ดังนั้นอย่าลังเลที่จะลดจำนวนตัวอักษรเหล่านั้นลงไป 5 ไบท์
Martin Ender

main (x, y) ใช้ไม่ได้กับ gcc ของฉัน อาจจำเป็นต้องมีตัวเลือกคอมไพเลอร์ แต่คุณสามารถแทนที่ main (x, y) ด้วย x; main (y)
Florian F

3

66 102 ไบต์

main(a,b,c,d,e){scanf("%d %d",&a,&b);e=1<<31;c=a&e;d=b&e;putchar(a-b?c&~d?48:d&~c?49:a-b&e?48:49:50);}

อ่านจำนวนเต็มจาก STDIN และพิมพ์0(a <b), 1(a> b) หรือ2(a == b)

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


แก้ไขฉันถ้าฉันผิด แต่ฉันเห็น <0 ในไตรภาคีภายในของคุณ
overactor

แก้ไข @overactor แล้ว
Martin Ender

3

52 ไบต์

น่าเศร้าที่อันนี้ใช้ได้กับจำนวนเต็มบวกเท่านั้น แต่ฉันคิดว่าแนวคิดของการใช้ตัวดำเนินการทางคณิตศาสตร์ล้วนน่าสนใจ:

main(a,b){scanf("%d%d",&a,&b);putchar(b%a/b-a%b/a);}

ขาออก:

  • รหัส ASCII 0xFF: น้อยกว่า b
  • รหัส ASCII 0x00: เท่ากับ b
  • รหัส ASCII 0x01: มากกว่า b

หากคุณจะเป็นจำนวนเต็มบวกเท่านั้นputchar(a/b-b/a)ก็จะยิ่งสั้นลงมาก
เดนนิส

@Dennis ที่สร้างเอาต์พุตที่ต่างกันเช่น (50,1) และ (51,1) แต่ฉันก็สามารถตัดให้สั้นลงได้
Digital Trauma

1
ใช่ไม่ได้คิดอย่างถูกต้อง ...
เดนนิส

2

66 ไบต์

main(a,b){scanf("%d%d",&a,&b);putchar((0l+b-a>>63)-(0l+a-b>>63));}

พิมพ์ไบต์ 0x00 ถ้าa == b, 0x01 ถ้าและถ้าa < b 0xffa > b

เนื่องจากไม่ใช่ ASCII หรืออักขระ ASCII ไม่พิมพ์ในโปรแกรม [ของ]และถ้ามีอะไรไม่ได้ต้องห้ามอย่างชัดเจนในคำถามแล้วมันจะได้รับอนุญาตอักขระ unprintable ในการส่งออกควรจะสมบูรณ์ดี


เวอร์ชันก่อนหน้าของฉันไม่รองรับการล้นได้ดีมาก สิ่งนี้ใช้ได้กับ x64 Linux โดยที่long64- บิต
เดนนิส

2

87 ตัวอักษร

main(a,b,c){scanf("%d%d",&a,&b);c=1<<31;a+=c;b+=c;puts(a^b?(unsigned)a/b?">":"<":"=");}

ใช้เคล็ดลับ 2 ^ 31 เพื่อแปลงเป็น int ที่ไม่ได้ลงชื่อ

การแบ่งส่วนให้กับ unsigned เพื่อจัดการบิตบนเป็นข้อมูลไม่ใช่ลงชื่อ

การใช้ ^ to XOR a และ b เมื่อพวกเขามีค่าเท่ากันจะได้ผลลัพธ์เป็น 0

การใช้เงื่อนไขที่ซ้อนกัน (?) เพื่อรับ "<", ">" หรือ "=" เพื่อป้อนเพื่อวาง ()


1

71 ไบต์

main(x,y,z){scanf("%d%d",&x,&y);putchar((z=x-y)?(z&(z>>31))?50:49:51);}

http://ideone.com/uvXm6c


อุดมคติของคุณมีวงเล็บอยู่รอบ ๆz=x-yและฉันค่อนข้างแน่ใจว่าพวกเขาจำเป็น นอกจากนี้คุณยังสามารถบันทึกตัวละครทั้งสองโดยใช้49, 50` และโดยตรงแทนการเพิ่ม51 48
Martin Ender

การมอบหมายมีความสำคัญต่ำกว่าผู้ประกอบการที่ประกอบไปด้วย: en.cppreference.com/w/c/language/operator_precedence
Martin Ender

รหัสของคุณด้านบนขาดเครื่องหมายอัฒภาคและใช้ไม่ได้-2000000000 2000000000รวมทั้งจำนวนเต็มอื่น ๆ ที่ทำให้เกิดการล้นในการลบ
COTO

1

68 ตัวอักษร

int main(a,b){scanf("%d%d",&a,&b);putchar(a-b?((unsigned)a-b)>>31:2);}

วางอักขระ ASCII 1, 2 หรือ 3 สำหรับน้อยกว่ามากกว่าหรือเท่ากับตามลำดับ


1
สิ่งนี้จะไม่ทำงานหากa-bล้น
Dennis

1

88 89 ไบต์

main(a,b){scanf("%d%d",&a,&b);a+=1<<31;b+=1<<31;for(;a&&b;a--)b--;putchar(a?b?48:49:50);}

เริ่มต้นโดยการเพิ่ม1<<31( INT_MIN) ไป A และ B INT_MINเพื่อให้สอดคล้อง จากนั้นลูปและลดค่า a และ b ทุกลูปจนกว่าจะเป็น 0 จากนั้นพิมพ์ 0, 1 หรือ 2 ขึ้นอยู่กับว่า a, b หรือทั้งสองเป็น 0

120 119 ไบต์

main(a,b,c){scanf("%d%d",&a,&b);c=1<<31;a^=c;b^=c;for(c~=c;!c;c/=2)if(a&c^b&c){putchar(a?48:49);return;}putchar(50);}

มันไม่ใช่ทางออกที่สั้นที่สุดเท่าที่จะเป็นไปได้ (หรือเพียงแค่คนที่มีความรู้เรื่อง C มากกว่าฉัน)

แนวคิดคือการปิดบังแต่ละบิตโดยเริ่มจากทางซ้ายและตรวจสอบความไม่เท่าเทียมกัน ที่เหลือควรอธิบายตัวเอง เนื่องจากตัวเลขที่ติดลบเริ่มต้นด้วย 1 a^=1<<31บิตครั้งแรกที่ผมกลับบิตแรกด้วย


ฉันไม่สามารถทดสอบการแก้ปัญหาของฉันในขณะนี้ดังนั้นโปรดชี้ข้อผิดพลาด
overactor

วิธีแก้ปัญหาแรกมีสองปัญหา: 1. ;)รอยยิ้มที่มีความสุขควรเป็น);รอยยิ้มที่น่าเศร้า 2. a&bทดสอบเฉพาะaและbมีบิตเหมือนกันเท่านั้น &&คุณจำเป็นต้อง
เดนนิส

@ เดนนิสคุณพูดถูกขอบคุณ
overactor

1

ฉันคิดว่าฉันจะไม่ลองเขียนรหัสย่อด้วยซ้ำ สิ่งที่ฉันจะพยายามคือทำการเปรียบเทียบในลักษณะที่พกพาได้ตามข้อมูลจำเพาะของ C99

int a, b;   // Let's assume these are initialized
int sign_a = a ? ((a|7)^2)%2 + ((a|7)^3)%2 : 0;

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

char result="\0<<>=<>>\0"[4+3*sign_a+sign_b]
if (!result) {   // signs matching means subtraction won't overflow
  int diff=a-b;
  int sign_diff=diff ? (diff|7^2)%2 + (diff|7^3)%2 : 0;
  result = ">=<"[1-sign_diff];
}

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


1

C 80 ตัวอักษร

a,b,c=1<<31;main(){scanf("%d%d",&a,&b);putchar(a^b?(a&c^b&c?a:a-b)&c?60:62:61);}

มันพิมพ์ '<', '>' หรือ '=' ตามที่ควร

C 63 ตัวอักษร

แนวทางใหม่:

a;main(b){scanf("%d%d",&a,&b);putchar(50+(0L+a-b>>42)+!(a-b));}

พิมพ์ '1', '2' หรือ '3'


1

ใน 64 chars ที่ไม่มี stdio.h

a,b;main(){scanf("%d%d",&a,&b);puts((a-b)>>31?"<":a^b?">":"=");}

พิมพ์ '>' ถ้า a> b, '<' ถ้า a <b, '=' ถ้า a == b int overflow เป็น UB อย่าล้น

// declare a and b as ints
a,b;

// defaults to int
main()
{
  scanf("%d%d",&a,&b);
   /*
    * (a-b)>>31 signbit of a-b
    * a^b a xor b -> 0 if they are equal
    */
  puts(((a-b)>>31) ? "<" : (a^b) ? ">" : "=");
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.