比較演算子なしでCまたはC ++の2つの整数を比較する


12

(stdinまたは引数として)入力として2つの符号付き整数を取り、最初の数が(1)より大きい、(2)より小さい、または(3)2番目に等しいかどうかに応じて3つの異なる出力を表示する最短プログラムを生成します数。

キャッチ

プログラムでは次のいずれも使用できません。

  • 標準の比較演算子:<><=>===!=
  • 離れてからの任意のライブラリ・ファイルconiostdioまたはiostream
  • 非ASCIIまたは印刷不能ASCII文字。

勝者

最短文字数のプログラムが勝ちます。


ライブラリファイルabs 含めずに(コンパイラがそれを知っているため)のようなものを使用することも許可されていないのでしょうか。
マーティンエンダー14

1
@MartinBüttnerはい、それは正しい仮定でしょう。:)
グローブ14

5
なぜC(++)に制限があるのですか?Cの基本型の移植性がないにもかかわらず、答えを移植可能にしたいのであれば、それを述べるべきです。それがarbitrary意的な制限である場合、1つの言語に対するarbitrary意的な制限はこのサイトでは人気がないことに注意する必要があります。
ピーターテイラー14

8
@PeterTaylorそれは挑戦の一部です。質問が言語にとらわれない場合は、まったく異なるボールゲームになります。それをC / C ++に制限すると、問題にアプローチするときに使用される戦略が変わります。より多くの人々の参加を促進するために、ほとんどの言語に質問を公開する必要があることを認識していますが、この特定の問題では、C / C ++とその特定の演算子とメソッドへの制限が課題の不可欠な部分です。
グローブ14

1
@EvilTeachはい; 質問で明示的に禁止されていないものがある場合、許可されます。
グローブ14

回答:


2

53バイト

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

出力の最初の文字のみが関連します。3つの異なる出力は次のとおりです。

  1. b> aの場合は '-'
  2. a == bの場合は「0」
  3. a> bの場合、その他の文字

sizeof(long)> sizeof(int)であるすべてのプラットフォームで、intの全入力範囲に対して機能します。

編集:ケース3に「+」を一意に印刷させるには、1文字余分にかかります:

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

Ouputs 00もしa > b-10あればa == b、と-1-1あればa < b


この種のコードと同様に、Cは動作を保証しません。long long64ビットを超えるint可能性があり、オーバーフローする可能性があるので、負の値を右にシフトした結果は実装定義です。ほとんどすべてのC派生の回答には同様の問題があります。
ヤンバーニエ14

1
@YannVernier:わかりました。100%絶対確実なソリューションはモンスターになると思います。安全に(シフトやオーバーフローなしで)できることは少し調整するだけなので、それを安全に行うにはオペランドを使用して長さを決定する必要がありますsizeof
COTO 14

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バイト

指数はゼロに丸められますが、右シフトは(実際には)「切り捨てられます」。それは死んだ景品です。

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

65 79バイト

負の数の別の顕著な特性は、負のモジュロを生成することです。これは整数表現にまったく依存しません。それは私の8ビットexcess-127トースターでも動作します!ああ、そしてを使用できるconioので、2バイトを節約してみません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 longよりも広いと仮定して大きな違いを処理しintます。


2つの整数を明確に解析%dするscanfには、sの間に区切り文字が必要であると確信しています。いいアイデアだ!
マーティンエンダー14

1
@マーティン:まあ、それはGCC で動作しますが、それが真正かどうかは本当にわかりません。
2014

つまり、入力a = 1, b = 23とをどのように区別しますかa = 12, b = 3123どちらの場合もSTDINを使用する必要はありませんか?
マーティンエンダー14

1
私が言ったように、それは(入力として、1 23および12 3入力として)動作するようです。
2014

2
ああ、入力にスペースを含めます。ええ、実際に動作することは驚くことではありません。
マーティンエンダー14

5

64 61文字

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

Prints the character values of -1, 0, and 1 for less than, equal to, or greater than, respectively.

This implementation relies on undefined behavior for b being of type int and for inputs outside the range INT_MIN / 2 to INT_MAX / 2. On platforms where signed overflow wraps around, whether 2s-complement (basically all of them) or sign-magnitude, it will fail for 25% of possible pairs of valid int. Interestingly (to me anyway), it will work correctly on platforms where signed overflow saturates.


a-bオーバーフローした場合、これは機能しません。
デニス14

残念ながらそれは事実ですが、比較演算子なしでこれを回避するプラットフォームにとらわれない方法は考えられませんでした。質問は、結果が有効でなければならない入力の範囲を指定しません。この回答は、間のすべての入力のための仕事に標準で保証されている-(2^14)2^14 - 1、すべての対応プラットフォーム上で、それはおそらく、ほとんどのプラットフォーム上で実質的により広い範囲のために動作します。この時点での他のすべての答えは、型のサイズ、型の相対的なサイズ、または表現に関する仮定を行います。
laindir

The question says two signed integers as input, so I'd say it has to work for all pairs. main(a,b) is already undefined behavior, so none of the answers is guaranteed to work. Nevermind portability.
Dennis

You're absolutely right regarding the undefined behavior, so my implementation really doesn't guarantee anything by the standard. I'll add a note indicating what its limitations are.
laindir

3

66 102 bytes

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

Reads the integers from STDIN and prints 0 (a < b), 1 (a > b) or 2 (a == b).

Edit: Now it should also work for differences which are too large to fit into a 32-bit integer. I'm sure That nested ternary can be shortened with some more bit-magic.


Correct me if I'm wrong, but I'm seeing a<0 in your inner ternary.
overactor

@overactor fixed
Martin Ender

3

52 bytes

Sadly this one only works for positive integers, but I thought the concept of using purely arithmetic operators was interesting:

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

Outputs:

  • ASCII code 0xFF: a less than b
  • ASCII code 0x00: a equal to b
  • ASCII code 0x01: a greater than b

If you're going only for positive integers, putchar(a/b-b/a) is a lot shorter.
Dennis

@Dennis that produces different outputs for example for (50,1) and (51,1). But I was able to shorten a bit though.
Digital Trauma

1
Yes, wasn't thinking properly...
Dennis

3

 59   54 characters

54 charcters with a compiler like gcc which doesn't balk at main(x,y):

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

59 characters otherwise:

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

Output:

  • ASCII code 0x00 if x < y
  • ASCII code 0xFF if x > y
  • ASCII code 0x01 if x == y

1
I can assure you, main(x,y) works in gcc, so feel free to drop those 5 bytes from your character count.
Martin Ender

main(x,y) doesn't work on my gcc. Maybe a compiler option is required. But you can replace main(x,y) by x;main(y).
Florian F

2

66 bytes

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

Prints the byte 0x00 if a == b, 0x01 if a < b and 0xff if a > b.

Since non-ASCII or non-printable ASCII character in [my] program and if anything is not explicitly forbidden in the question, then it is permitted, unprintable character in the output should be completely fine.


My previous version didn't handle overflow very well. This works on x64 Linux, where long is 64-bits.
Dennis

2

87 characters

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

Using the 2^31 trick to convert to unsigned int's

Casting the division to unsigned to handle the upper bit as data, not sign

Using ^ to XOR a and b, when they are equal this returns 0

Using nested conditionals (?) to get "<",">", or "=" to feed to puts()


1

71 bytes

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

http://ideone.com/uvXm6c


Your ideone has parentheses around z=x-y and I'm pretty sure they are necessary. You can also save two characters by using 49, 50` and 51 directly, instead of adding 48.
Martin Ender

Assignment has a lower precedence than the ternary operator: en.cppreference.com/w/c/language/operator_precedence
Martin Ender

Your code above is missing a semicolon, and it fails for -2000000000 2000000000, as well as any other combination of integers that cause overflow in the subtraction.
COTO

1

68 characters

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

Puts ASCII character 1, 2 or 3 for less than, greater than or equal, respectively.


1
This won't work if a-b overflows.
Dennis

1

88 89 bytes

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

This starts by adding 1<<31 (INT_MIN) to a and b, so that 0 now corresponds INT_MIN. Then loops and decrements a and b every loop until either is 0, then prints 0, 1 or 2 depending on whether a, b or both are 0.

120 119 bytes

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

It's not the shortest solution as it is but might be golfed down a bit by better golfer than me. (Or just people with more knowledge of C than me)

The idea is to mask each bit, starting from the left one and checking for inequality. The rest should explain itself. Since negative numbers start with a 1 bit, I first invert the first bit with a^=1<<31.


I can't test my solutions for the moment, so feel free to point out mistakes.
overactor

The first solution has a couple of problems: 1. The happy ;) smiley should be a sad ); smiley. 2. a&b only tests if a and b have bits in common; you need &&.
Dennis

@Dennis, you're right, thanks.
overactor

1

I think I'm not even going to try at writing short code. What I will attempt is to perform this comparison in a way that is portable per the C99 spec.

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

The modulo operator preserves sign, but it may well produce a zero (including negative zero), so we ensure we have both an odd and even value for it to check (even without knowing if we are using ones complement). Arithmetic operations may overflow, but bitwise will not, and by ensuring there are bits both set and cleared we avoid inadvertently converting our number into negative zero or a trap value. The fact that two operations are required to do so oddly should not matter, because the possible trap representation doesn't cause undefined behaviour until put in an lvalue. Doing the operation with bit 0 toggled ensures we get exactly one non-zero remainder. Armed with the knowledge of both signs, we can decide how to proceed with the comparison.

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

This method may be one of a few that permit extracting the sign of an integer negative zero. We solve that by explicitly checking for zero. If we were golfing for real, we could of course allow the comparison of two zeros to also perform the subtraction.


1

C 80 chars

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

It prints '<', '>' or '=', as it should.

C 63 chars

A new approach:

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

Prints '1', '2' or '3'.


1

In 64 chars without stdio.h

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

prints '>' if a > b, '<' if a < b, '=' if a == b int overflow is UB. Just don't overflow.

// 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.