Bandingkan dua bilangan bulat dalam C atau C ++ tanpa operator pembanding

12

Menghasilkan program terpendek yang mengambil dua bilangan bulat yang ditandatangani sebagai input (melalui stdin atau sebagai argumen) dan menampilkan 3 output yang berbeda tergantung pada apakah angka pertama adalah (1) lebih besar dari, (2) lebih kecil dari, atau (3) sama dengan yang kedua jumlah.

Tangkapan

Anda tidak dapat menggunakan salah satu dari yang berikut ini di program Anda:

  • Operator perbandingan standar: <, >, <=, >=, ==, !=.
  • Setiap file library terlepas dari conio, stdioatau iostream.
  • Karakter ASCII yang tidak dapat dicetak atau yang tidak dapat dicetak.

Pemenang

Program dengan jumlah karakter terpendek akan menang.

belukar
sumber
Saya kira menggunakan hal-hal seperti abs tanpa menyertakan file perpustakaan (karena kompiler tahu juga) tidak diperbolehkan?
Martin Ender
1
@ MartinBüttner ya, itu akan menjadi asumsi yang benar. :)
grove
5
Mengapa batasan untuk C (++)? Jika itu karena Anda ingin jawaban menjadi portabel meskipun tidak dapat diaksesnya tipe dasar C maka Anda harus menyatakannya. Jika ini adalah pembatasan sewenang-wenang maka Anda harus menyadari bahwa pembatasan sewenang-wenang untuk satu bahasa tidak populer di situs ini.
Peter Taylor
8
@PeterTaylor itu bagian dari tantangan. Ini akan menjadi ballgame yang sangat berbeda sama sekali jika pertanyaannya adalah bahasa-agnostik. Membatasinya menjadi C / C ++ mengubah strategi yang digunakan ketika mendekati masalah. Saya menyadari perlunya pertanyaan terbuka untuk sebagian besar bahasa untuk mempromosikan partisipasi oleh lebih banyak orang, tetapi dalam masalah khusus ini pembatasan C / C ++ dan operator dan metode spesifik mereka merupakan bagian integral dari tantangan.
Grove
1
@ EvilTeach ya; jika ada sesuatu yang tidak dilarang secara eksplisit dalam pertanyaan, maka hal itu diizinkan.
Grove

Jawaban:

2

53 byte

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

Hanya karakter pertama dari output yang relevan. Tiga output yang berbeda adalah:

  1. '-' jika b> a
  2. '0' jika a == b
  3. karakter lain apa pun jika a> b

Ia bekerja untuk berbagai input int penuh pada semua platform di mana sizeof (panjang)> sizeof (int).

Sunting: biayanya satu karakter tambahan untuk membuat case 3 mencetak '+' sebagai gantinya:

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

Mungkin saya melewatkan sesuatu dalam aturan, tapi ...

81 byte

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

Ouputs 00jika a > b, -10jika a == b, dan -1-1jika a < b.

COTO
sumber
Sama umum dengan kode semacam ini, C tidak menjamin itu berfungsi. long longbisa lebih dari 64 bit, intbisa lebih besar sehingga Anda bisa meluap, hasil pergeseran nilai negatif yang tepat adalah implementasi didefinisikan. Hampir semua jawaban yang diturunkan dari C memiliki masalah yang sama.
Yann Vernier
1
@YannVernier: Dipahami. Saya menduga solusi 100% sangat mudah akan menjadi monster, karena satu-satunya hal yang bisa kita lakukan dengan aman (yaitu tanpa bergeser atau melimpah) agak membingungkan, dan untuk melakukannya dengan aman kita harus menentukan panjang operan menggunakan sizeof.
COTO
6

90 byte

Jika kita dapat menggunakan stdio, mengapa tidak menggunakan kemampuan pemformatannya untuk melakukan perbandingan?

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

Mengasumsikan penyandian yang kompatibel dengan ASCII dan sedikit-endianness.

72 byte

Quotients dibulatkan ke nol tetapi shift kanan (dalam praktiknya) "dibulatkan ke bawah". Itu hadiah mati.

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

65 79 byte

Properti lain yang membedakan bilangan negatif adalah bahwa mereka menghasilkan modulo negatif. Yang ini tidak bergantung pada representasi integer sama sekali; bahkan bekerja pada 8-bit pemanggang kelebihan-127 saya! Oh, dan karena kita bisa menggunakan conio, mengapa tidak menyimpan dua byte dengan putch? Sekarang, jika saya hanya dapat menemukan salinan TurboC saya ...

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

EDIT : Tangani perbedaan besar dengan asumsi long longlebih lebar dari int.

Elo
sumber
Saya cukup yakin Anda memerlukan pembatas antara %ds di Anda scanfuntuk mengurai dua bilangan bulat. Ide yang bagus!
Martin Ender
1
@ Martin: Ya, itu bekerja dengan GCC, tapi saya benar-benar tidak yakin apakah itu bonafid.
Ell
Yang saya maksud adalah, bagaimana Anda membedakan antara input a = 1, b = 23dan a = 12, b = 3. Tidakkah Anda perlu memakai 123STDIN dalam kedua kasus itu?
Martin Ender
1
Seperti yang saya katakan, tampaknya berfungsi (dengan 1 23dan 12 3sebagai input).
Ell
2
Ohhh, Anda memasukkan spasi dalam input. Ya, saya tidak terkejut kalau itu berhasil, sebenarnya.
Martin Ender
5

64 61 karakter

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

Mencetak nilai karakter -1, 0, dan 1 masing-masing kurang dari, sama dengan, atau lebih besar dari.

Implementasi ini bergantung pada perilaku undefined untuk bmenjadi jenis intdan masukan di luar jangkauan INT_MIN / 2untuk INT_MAX / 2. Pada platform tempat limpahan yang ditandatangani membungkus, baik pelengkap 2s (pada dasarnya semuanya) atau sign-magnitude, itu akan gagal untuk 25% dari kemungkinan pasangan yang valid int. Menariknya (bagi saya), ini akan bekerja dengan benar pada platform di mana jenuh yang masuk ditandai.

laindir
sumber
Ini tidak akan berfungsi jika a-bmeluap.
Dennis
Sayangnya itu benar, tetapi saya tidak bisa memikirkan cara agnostik platform apa pun untuk menghindari ini tanpa operator perbandingan. Pertanyaannya tidak menentukan kisaran input yang hasilnya harus valid. Jawaban ini dijamin oleh standar untuk bekerja untuk semua input antara -(2^14)dan 2^14 - 1pada semua platform yang sesuai, dan mungkin akan bekerja untuk kisaran yang jauh lebih besar pada kebanyakan platform. Semua jawaban lain pada titik ini membuat asumsi tentang ukuran tipe, ukuran relatif tipe, atau representasi.
laindir
Pertanyaannya mengatakan dua bilangan bulat yang ditandatangani sebagai input , jadi saya akan mengatakan itu harus bekerja untuk semua pasangan. main(a,b)sudah merupakan perilaku yang tidak terdefinisi, sehingga tidak ada jawaban yang dijamin akan berfungsi. Nevermind portabilitas.
Dennis
Anda benar tentang perilaku yang tidak terdefinisi, jadi implementasi saya benar-benar tidak menjamin apa pun dengan standar. Saya akan menambahkan catatan yang menunjukkan apa batasannya.
laindir
3

66 102 byte

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);}

Membaca bilangan bulat dari STDIN dan mencetak 0(a <b), 1(a> b) atau 2(a == b).

Sunting: Sekarang ini juga berfungsi untuk perbedaan yang terlalu besar untuk masuk ke dalam bilangan bulat 32-bit. Saya yakin terary bersarang itu dapat disingkat dengan sedikit lebih banyak sihir.

Martin Ender
sumber
Koreksi saya jika saya salah, tetapi saya melihat <0 di ternary batin Anda.
overactor
@ overactor diperbaiki
Martin Ender
3

52 byte

Sayangnya ini hanya bekerja untuk bilangan bulat positif, tetapi saya pikir konsep menggunakan operator aritmatika murni menarik:

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

Output:

  • Kode ASCII 0xFF: kurang dari b
  • Kode ASCII 0x00: sama dengan b
  • Kode ASCII 0x01: lebih besar dari b
Trauma Digital
sumber
Jika Anda hanya ingin bilangan bulat positif, putchar(a/b-b/a)jauh lebih pendek.
Dennis
@ Dennis yang menghasilkan output yang berbeda misalnya untuk (50,1) dan (51,1). Tapi saya bisa mempersingkat sedikit.
Digital Trauma
1
Ya, tidak berpikir dengan benar ...
Dennis
3

 59    54 karakter

54 karakter dengan kompiler seperti gcc yang tidak menolak di main(x,y):

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

59 karakter sebaliknya:

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

Keluaran:

  • Kode ASCII 0x00 jika x <y
  • Kode ASCII 0xFF jika x> y
  • Kode ASCII 0x01 jika x == y
Todd Lehman
sumber
1
Saya dapat meyakinkan Anda, main(x,y)bekerja di gcc, jadi jangan ragu untuk menjatuhkan 5 byte dari jumlah karakter Anda.
Martin Ender
main (x, y) tidak berfungsi pada gcc saya. Mungkin opsi kompiler diperlukan. Tetapi Anda dapat mengganti main (x, y) dengan x; main (y).
Florian F
2

66 byte

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

Mencetak byte 0x00 if a == b, 0x01 if a < bdan 0xff if a > b.

Karena non-ASCII atau karakter ASCII yang tidak dapat dicetak dalam program [saya] dan jika ada sesuatu yang tidak dilarang secara eksplisit dalam pertanyaan, maka diizinkan , karakter yang tidak diinginkan dalam output harus sepenuhnya baik-baik saja.

Dennis
sumber
Versi saya sebelumnya tidak menangani overflow dengan sangat baik. Ini berfungsi di x64 Linux, di mana long64-bit.
Dennis
2

87 karakter

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

Menggunakan trik 2 ^ 31 untuk mengonversi ke int yang tidak ditandatangani

Casting divisi untuk unsigned untuk menangani bit atas sebagai data, bukan masuk

Menggunakan ^ ke XOR a dan b, ketika mereka sama ini mengembalikan 0

Menggunakan bersarang kondisi (?) Untuk mendapatkan "<", ">", atau "=" untuk memberi makan ke menempatkan ()

Pelle
sumber
1

71 byte

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

http://ideone.com/uvXm6c

Michael M.
sumber
Ideone Anda memiliki tanda kurung di sekitar z=x-ydan saya cukup yakin mereka perlu. Anda juga dapat menyimpan dua karakter dengan menggunakan 49, 50` dan 51langsung, alih-alih menambahkan 48.
Martin Ender
Penugasan memiliki prioritas lebih rendah daripada operator ternary: en.cppreference.com/w/c/language/operator_precedence
Martin Ender
Kode Anda di atas tidak memiliki tanda titik koma, dan gagal untuk -2000000000 2000000000, serta kombinasi bilangan bulat lainnya yang menyebabkan overflow dalam pengurangan.
COTO
1

68 karakter

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

Letakkan karakter ASCII 1, 2 atau 3 masing-masing kurang dari, lebih besar atau sama.

CompuChip
sumber
1
Ini tidak akan berfungsi jika a-bmeluap.
Dennis
1

88 89 byte

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);}

Ini dimulai dengan menambahkan 1<<31( INT_MIN) ke a dan b, sehingga 0 sekarang sesuai INT_MIN. Kemudian lilitkan dan kurangi a dan b setiap loop sampai 0, kemudian cetak 0, 1 atau 2 tergantung pada apakah a, b atau keduanya 0.

120 119 byte

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);}

Ini bukan solusi terpendek seperti itu tetapi mungkin golf sedikit lebih baik dari saya. (Atau hanya orang yang memiliki pengetahuan lebih banyak tentang C daripada saya)

Idenya adalah untuk menutupi setiap bit, mulai dari yang kiri dan memeriksa ketidaksetaraan. Selebihnya harus menjelaskan sendiri. Karena angka negatif dimulai dengan 1 bit, saya pertama-tama membalikkan bit pertama dengan a^=1<<31.

overactor
sumber
Saya tidak dapat menguji solusi saya untuk saat ini, jadi silakan tunjukkan kesalahan.
overactor
Solusi pertama memiliki beberapa masalah: 1. ;)Smiley yang bahagia harus tersenyum yang sedih );. 2. a&bhanya menguji jika adan bmemiliki bit yang sama; kamu membutuhkan &&.
Dennis
@ Dennis, Anda benar, terima kasih.
overactor
1

Saya pikir saya bahkan tidak akan mencoba menulis kode pendek. Apa yang akan saya coba adalah melakukan perbandingan ini dengan cara yang portabel menurut spesifikasi C99.

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

Operator modulo mempertahankan tanda, tetapi mungkin menghasilkan nol (termasuk nol negatif), jadi kami memastikan kami memiliki nilai ganjil dan genap untuk diperiksa (bahkan tanpa mengetahui apakah kami menggunakan komplemen yang). Operasi aritmatika mungkin meluap, tetapi bitwise tidak akan, dan dengan memastikan ada bit yang ditetapkan dan dihapus, kita menghindari secara tidak sengaja mengubah angka kita menjadi nol negatif atau nilai perangkap. Fakta bahwa dua operasi diperlukan untuk melakukannya secara aneh seharusnya tidak menjadi masalah, karena representasi perangkap yang mungkin tidak menyebabkan perilaku yang tidak ditentukan sampai dimasukkan ke dalam nilai yang tinggi. Melakukan operasi dengan bit 0 toggled memastikan kami mendapatkan tepat satu sisanya. Berbekal pengetahuan tentang kedua tanda, kita dapat memutuskan bagaimana melanjutkan dengan perbandingan.

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];
}

Metode ini mungkin salah satu dari sedikit yang memungkinkan mengekstraksi tanda nol negatif integer. Kami menyelesaikannya dengan secara eksplisit memeriksa nol. Jika kita benar-benar bermain golf, tentu saja kita bisa membiarkan perbandingan dua nol untuk melakukan pengurangan.

Yann Vernier
sumber
1

C 80 karakter

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);}

Mencetak '<', '>' atau '=', sebagaimana mestinya.

C 63 karakter

Pendekatan baru:

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

Mencetak '1', '2' atau '3'.

Florian F
sumber
1

Dalam 64 karakter tanpa stdio.h

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

mencetak '>' jika a> b, '<' jika a <b, '=' jika a == b int overflow adalah UB. Hanya saja, jangan meluap.

// 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) ? ">" : "=");
}
ViralTaco_
sumber