Karşılaştırma işleçleri olmadan C veya C ++ 'da iki tamsayıyı karşılaştırma


13

Girilen (stdin veya bağımsız değişkenler olarak) iki işaretli tam sayıyı alan ve ilk sayının (1) büyükten (2) küçükten (2) küçük ya da (3) eşit olmasına bağlı olarak 3 farklı çıkış gösteren en kısa programı üretin numara.

Yakalayış

Programınızda aşağıdakilerden hiçbirini kullanamazsınız:

  • Standart karşılaştırma operatörleri: <, >, <=, >=, ==, !=.
  • Dışında herhangi bir kitaplık dosyası conio, stdioya da iostream.
  • ASCII olmayan veya yazdırılamayan ASCII karakterleri.

Kazanan

En az karakter içeren program kazanır.


(Derleyici zaten biliyor çünkü) kütüphane dosyası dahil abs etmeden gibi şeyler kullanarak varsayalım ya da izin verilmiyor?
Martin Ender

1
@ MartinBüttner evet, bu doğru bir varsayım olurdu. :)
grove

5
Neden C (++) kısıtlaması? Eğer C'nin temel tiplerinin ölçülemezliğine rağmen cevapların taşınabilir olmasını istiyorsanız, bunu belirtmelisiniz. Bu rastgele bir kısıtlama ise, bu sitede bir dile rasgele kısıtlamaların popüler olmadığını bilmelisiniz.
Peter Taylor

8
@PeterTaylor bu mücadelenin bir parçası. Sorunun dile agnostik olması çok farklı bir top oyunu olurdu. C / C ++ ile sınırlamak, soruna yaklaşırken kullanılan stratejileri değiştirir. Daha fazla insanın katılımını teşvik etmek için soruların çoğuna açık olma ihtiyacını kabul ediyorum, ancak bu özel problemde C / C ++ ve onların özel operatörleri ve yöntemleri ile ilgili kısıtlama, mücadelenin ayrılmaz bir parçasıdır.
grove

1
@EvilTeach evet; soruda açıkça bir şey yasaklanmamışsa, buna izin verilir.
korusu

Yanıtlar:


2

53 bayt

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

Çıktının yalnızca ilk karakteri önemlidir. Üç farklı çıktı:

  1. '-' b> a ise
  2. == b ise '0'
  3. a> b ise başka herhangi bir karakter

Sizeof (long)> sizeof (int) olan tüm platformlarda int'in tam girdi aralığı için çalışır.

Düzenleme: Durum 3'ün benzersiz bir şekilde '+' yazdırması için bir ekstra karaktere mal olur:

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

6

Belki kurallarda bir şey eksik ama ...

81 bayt

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

Çıkışlardan 00eğer a > b, -10eğer a == b, ve -1-1eğer a < b.


Bu tür bir kod kadar yaygın olan C, çalıştığını garanti etmez. long long64 bitten fazla intolabilir , taşabildiğiniz kadar büyük olabilir, negatif değerleri sağa kaydırmanın sonucu uygulama olarak tanımlanmıştır. Hemen hemen C-kaynaklı cevapların benzer sorunları vardır.
Yann Vernier

1
@YannVernier: Anlaşıldı. % 100 kusursuz bir çözümün bir canavar olacağını tahmin ediyorum, çünkü güvenli bir şekilde yapabileceğimiz tek şey (yani, kaydırma veya taşma olmadan) biraz bükülüyor ve bunu güvenli bir şekilde yapmak için, işlenenlerin uzunluğunu belirlememiz gerekiyor sizeof.
COTO

6

90 bayt

Kullanabiliyorsak stdio, karşılaştırma yapmak için neden biçimlendirme özelliklerini kullanmıyorsunuz?

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

ASCII uyumlu kodlama ve az endianite olduğunu varsayar.

72 bayt

Bölümler sıfıra yuvarlanır, ancak sağ kaymalar (pratikte) "yuvarlanır". Bu ölü bir hediye.

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

65 79 bayt

Negatif sayıların bir diğer ayırt edici özelliği, negatif modulo üretmeleridir. Bu hiçbir zaman tamsayı temsiline bağlı değildir; hatta benim 8-bit fazla 127 ekmek kızartma makinesi üzerinde çalışıyor! Oh, ve kullanabileceğimiz için conio, neden iki bayt kaydetmiyoruz putch? Şimdi, sadece TurboC kopyamı bulabilseydim ...

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

DÜZENLEME : Büyük farkları long longdaha geniş olduğunu varsayarak ele alın int.


Kesinlikle iki tamsayı ayrıştırmak için %ds arasında bir sınırlayıcı gerekir eminim scanf. Güzel fikir olsa!
Martin Ender

1
@Martin: GCC ile çalışıyor , ama gerçekten iyi olup olmadığından emin değilim.
Ell

Demek istediğim, girdiler a = 1, b = 23ve arasındaki farkı nasıl ayırt edersiniz a = 12, b = 3. Her 123iki durumda da STDIN kullanmanıza gerek kalmaz mı?
Martin Ender

1
Dediğim gibi, ( girdi ile 1 23ve 12 3girdi olarak) çalışıyor gibi görünüyor .
Ell

2
Ohhh, girdiye boşluklar ekliyorsunuz. Evet, aslında işe yaradığına şaşırmadım.
Martin Ender

5

64 61 karakter

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

-1, 0 ve 1 karakter değerlerini sırasıyla küçük, eşit ya da büyük için yazdırır.

Bu uygulama için istenmeyen davranışlara dayanır btipte olduğu intve aralığın dışında girişler için INT_MIN / 2için INT_MAX / 2. İmzalı taşmanın etrafını saran platformlarda, ister 2s-tamamlayıcı (temel olarak tümü) veya işaret büyüklüğü olsun, olası geçerli çiftlerin% 25'i için başarısız olur int. İlginç bir şekilde (yine de benim için), imzalı taşmanın doyduğu platformlarda doğru şekilde çalışacaktır.


Taşmalar durumunda bu çalışmaz a-b.
Dennis

Ne yazık ki bu doğru, ama karşılaştırma operatörleri olmadan bunu önlemek için herhangi bir platform agnostik yol düşünemedim. Soru, sonuçların geçerli olması gereken bir dizi girdi belirtmiyor. Bu cevap, standart tarafından tüm uyumlu platformlar arasındaki -(2^14)ve tüm girişler için çalışacak şekilde garanti edilmektedir ve 2^14 - 1muhtemelen çoğu platformda önemli ölçüde daha geniş bir aralıkta çalışacaktır. Bu noktadaki diğer tüm cevaplar, türün boyutu, türlerin göreli boyutları veya temsiliyle ilgili varsayımlar yapar.
laindir

Soru, giriş olarak iki imzalı tamsayı söylüyor , bu yüzden tüm çiftler için çalışması gerektiğini söyleyebilirim. main(a,b)zaten tanımlanmamış bir davranış olduğundan, yanıtların hiçbirinin çalışacağı garanti edilmez. Boşverilebilirlik.
Dennis

Tanımlanmamış davranış konusunda kesinlikle haklısınız, bu yüzden benim uygulamam standart tarafından hiçbir şey garanti etmiyor. Sınırlamalarının ne olduğunu belirten bir not ekleyeceğim.
laindir

4

 59    54 karakter

Gcc gibi bir derleyiciye sahip 54 charter main(x,y):

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

Aksi takdirde 59 karakter:

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

Çıktı:

  • X <y ise ASCII kodu 0x00
  • X> y ise ASCII kodu 0xFF
  • X == y ise ASCII kodu 0x01

1
Sizi temin ederim, main(x,y)gcc olarak çalışır, bu yüzden karakter sayınızdan bu 5 baytı bırakmaktan çekinmeyin.
Martin Ender

main (x, y) benim gcc üzerinde çalışmıyor. Belki bir derleyici seçeneği gereklidir. Ancak main (x, y) 'yi x; main (y) ile değiştirebilirsiniz.
Florian F

3

66 102 bayt

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 tam sayılarını okur ve 0(a <b), 1(a> b) veya 2(a == b) yazdırır .

Düzenleme: Şimdi 32 bit tam sayıya sığmayacak kadar büyük farklılıklar için de çalışmalıdır. Eminim ki bu iç içe üçlü, biraz daha büyü ile kısaltılabilir.


Yanılıyorsam düzelt ama iç üçlüde <0 görüyorum.
overactor

@overactor sabit
Martin Ender

3

52 bayt

Ne yazık ki bu sadece pozitif tamsayılar için çalışıyor, ancak tamamen aritmetik operatörleri kullanma kavramının ilginç olduğunu düşündüm:

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

Çıktılar:

  • ASCII kodu 0xFF: b'den küçük
  • ASCII kodu 0x00: b'ye eşit
  • ASCII kodu 0x01: b'den büyük

Sadece pozitif tamsayılar için gidiyorsanız, putchar(a/b-b/a)çok daha kısadır.
Dennis

@ (50,1) ve (51,1) için farklı çıktılar üreten kumaş. Ama yine de biraz kısaltabildim.
Dijital Travma

1
Evet, düzgün düşünmüyordu ...
Dennis

2

66 bayt

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

Bayt 0x00 if a == b, 0x01 if a < bve 0xff if yazdırır a > b.

Yana [my] programda olmayan ASCII veya olmayan yazdırılabilir ASCII karakteri ve her şey açıkça söz konusu yasak değilse, o zaman izin verilir , yazdırılamayan karakter çıktı tamamen iyi olmalıdır.


Önceki sürümüm taşmayı çok iyi işlemedi. Bu long, 64 bitlik x64 Linux'ta çalışır .
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?">":"<":"=");}

İmzasız int'lere dönüştürmek için 2 ^ 31 hile kullanma

Üst biti işaret olarak değil veri olarak işlemek için bölümü imzasız olarak döküm

^ İle XOR a ve b arasında, eşit olduklarında 0 döndürür

"<", ">" Veya puts () öğesine beslemek için "=" elde etmek için iç içe koşul (?) Kullanma


1

71 bayt

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

http://ideone.com/uvXm6c


İdne'nizin etrafında parantez var z=x-yve bunların gerekli olduğundan eminim. Ayrıca eklemek yerine 49, 50` ve 51doğrudan kullanarak iki karakter kaydedebilirsiniz 48.
Martin Ender


Yukarıdaki kodunuzda noktalı virgül eksik -2000000000 2000000000ve çıkartmada taşmaya neden olan diğer tamsayı kombinasyonlarının yanı sıra başarısız oluyor .
COTO

1

68 karakter

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

ASCII karakteri 1, 2 veya 3'ü sırasıyla daha küçük, büyük veya eşit olarak koyar.


1
Taşmalar durumunda bu çalışmaz a-b.
Dennis

1

88 89 bayt

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

Bu , a ve b'ye 1<<31( INT_MIN) eklenerek başlar , böylece 0 şimdi karşılık gelir INT_MIN. Sonra a ve b'yi her bir döngü 0 olana kadar döngüler ve azaltır, ardından a, b veya her ikisinin 0 olmasına bağlı olarak 0, 1 veya 2 yazdırır.

120 119 bayt

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

Olduğu gibi en kısa çözüm değil ama benden daha iyi golfçü tarafından biraz golf olabilir. (Ya da sadece benden daha fazla C bilgisi olan insanlar)

Fikir soldan başlayıp eşitsizliği kontrol ederek her bir biti maskelemektir. Gerisi kendini açıklamalıdır. Negatif sayılar 1 bit ile başladığından, önce ilk biti ters çeviririm a^=1<<31.


Çözümlerimi şimdilik test edemiyorum, bu yüzden hataları belirtmekten çekinmeyin.
overactor

İlk çözümün birkaç sorunu var: 1. Mutlu ;)surat üzgün bir surat olmalı );. 2. a&bYalnızca test ise ave bortak bitleri sahiptir; ihtiyacınız var &&.
Dennis

@Dennis, haklısın, teşekkürler.
Overactor

1

Kısa kod yazmayı denemeyeceğimi düşünüyorum. Bu karşılaştırmayı C99 spesifikasyonuna göre taşınabilir bir şekilde yapmaya çalışacağım.

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

Modulo operatörü işareti korur, ancak sıfır (negatif sıfır dahil) üretebilir, bu yüzden kontrol etmek için hem tek hem de eşit bir değere sahip olduğumuzu garanti ederiz (tamamlayıcı kullanıp kullanmadığımızı bilmeden bile). Aritmetik işlemler taşabilir, ancak bitsel olmayacaktır ve hem ayarlanmış hem de temizlenmiş bitler bulunduğundan, sayımızı yanlışlıkla negatif sıfıra veya bir tuzak değerine dönüştürmekten kaçınırız. İki işlemin garip bir şekilde yapılması gerektiği önemli değildir, çünkü olası tuzak temsili bir değer biçilene kadar tanımlanmamış davranışa neden olmaz. İşlemi bit 0 değiştirilmiş olarak yapmak, tam olarak bir sıfır olmayan geri kalan elde etmemizi sağlar. Her iki işaretin bilgisiyle donanmış, karşılaştırmaya nasıl devam edeceğimize karar verebiliriz.

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

Bu yöntem, bir tamsayı negatif sıfır işaretinin çıkarılmasına izin veren birkaç yöntemden biri olabilir. Bunu açıkça sıfır kontrol ederek çözüyoruz. Eğer gerçekten golf oynasaydık, elbette çıkarma yapmak için iki sıfırın karşılaştırılmasına izin verebilirdik.


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

Gerektiği gibi '<', '>' veya '=' yazdırır.

C 63 karakter

Yeni bir yaklaşım:

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

'1', '2' veya '3' yazdırır.


1

Stdio.h içermeyen 64 karakterde

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

a> b ise '>', a <b ise '<', a == b int taşması UB ise '=' yazar. Sadece taşma.

// 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) ? ">" : "=");
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.