비교 연산자없이 C 또는 C ++에서 두 정수 비교


13

두 개의 부호있는 정수를 입력으로 (stdin 또는 arguments를 통해) 취하고 첫 번째 숫자가 (1)보다 크거나 (2) 작거나 (3) 두 번째와 같은지 여부에 따라 3 개의 다른 출력을 표시하는 가장 짧은 프로그램을 생성하십시오. 번호.

캐치

프로그램에서 다음을 사용할 수 없습니다.

  • 표준 비교 연산자 : <, >, <=, >=, ==, !=.
  • 떨어져에서 모든 라이브러리 파일 conio, stdio또는 iostream.
  • ASCII가 아닌 문자 또는 인쇄 할 수없는 ASCII 문자

승자

문자 수가 가장 적은 프로그램이 승리합니다.


내가 좋아하는 일을 사용한다고 가정 abs 하지 않고 라이브러리 파일 (컴파일러는 어쨌든 그것을 알고 있기 때문에) 중 하나 허용되지 않는 등?
Martin Ender

1
@ MartinBüttner 네, 맞습니다. :)
grove

5
왜 C (++)로 제한합니까? C의 기본 유형의 이식성에도 불구하고 답변을 이식성이 있기를 원한다면 그 사실을 명시해야합니다. 임의의 제한 인 경우이 사이트에서 한 언어에 대한 임의의 제한이 인기가 없음을 알고 있어야합니다.
피터 테일러

8
@PeterTaylor 그것은 도전의 일부입니다. 질문이 언어에 구애받지 않으면 완전히 다른 볼 게임이 될 것입니다. C / C ++로 제한하면 문제에 접근 할 때 사용되는 전략이 변경됩니다. 더 많은 사람들의 참여를 촉진하기 위해 대부분의 언어에 대한 질문이 필요하다는 것을 알고 있습니다. 그러나이 특정한 문제에서 C / C ++와 그 특정 연산자와 방법에 대한 제한은 도전의 핵심 부분입니다.
그 로브

1
@EvilTeach 예; 질문에 명시 적으로 금지되어 있지 않은 것이 있으면 허용됩니다.
그 로브

답변:


2

53 바이트

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

출력의 첫 문자 만 관련이 있습니다. 세 가지 다른 출력은 다음과 같습니다.

  1. b> a 인 경우 '-'
  2. a == b 인 경우 '0'
  3. a> b 인 경우 다른 문자

sizeof (long)> sizeof (int) 인 모든 플랫폼에서 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-1경우 a < b.


이러한 종류의 코드와 마찬가지로 C는 작동한다고 보장하지 않습니다. long long64 비트 이상일 int수 있고, 클 수 있으므로 오버플로 할 수 있습니다. 음수 값을 올바르게 이동하면 결과가 구현 정의됩니다. 거의 모든 C 파생 답변에는 비슷한 문제가 있습니다.
Yann Vernier

1
@YannVernier : 이해했습니다. 우리가 안전하게 할 수있는 유일한 것은 (즉, 이동 또는 오버플로가없는) 비트 twiddling이기 때문에 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 바이트

몫은 0으로 반올림되지만 오른쪽 이동은 "실제로 반올림"됩니다. 그것은 죽은 공짜입니다.

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

65 79 바이트

음수의 또 다른 특징은 음수 모듈로를 생성한다는 것입니다. 이것은 정수 표현에 전혀 의존하지 않습니다. 심지어 8 비트 초과 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.


두 정수를 명확하게 구문 분석 하려면 %ds 사이에 구분 기호가 필요하다고 확신합니다 scanf. 그래도 좋은 생각입니다!
Martin Ender

1
@ 마틴 : 글쎄, 그것은 GCC와 함께 작동 하지만 , 그것이 진짜인지 확실하지 않습니다.
Ell

내 말은 입력 a = 1, b = 23과를 어떻게 구분 하는가하는 것 a = 12, b = 3입니다. 123두 경우 모두 STDIN 을 착용 할 필요가 없습니까?
Martin Ender

1
내가 말했듯이, (작동하도록 보인다 1 2312 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. 부호있는 오버플로가 줄어드는 플랫폼에서 2 초 (기본적으로 모두) 또는 부호 크기에 관계없이 유효한 쌍의 25 %가 실패합니다 int. 흥미롭게도 (어쨌든 나에게) 서명 된 오버플로가 포화되는 플랫폼에서 올바르게 작동합니다.


a-b오버플로가 발생하면 작동하지 않습니다 .
Dennis

슬프게도 그것은 사실이지만 비교 연산자없이 이것을 피할 수있는 플랫폼에 무관심한 방법을 생각할 수 없었습니다. 질문은 결과가 유효해야하는 입력 범위를 지정하지 않습니다. 이 답변은 표준에 의해 모든 호환 플랫폼 간 -(2^14)2^14 - 1모든 호환 플랫폼에서 작동하도록 보장되며 대부분의 플랫폼에서 실질적으로 더 큰 범위에서 작동합니다. 이 시점의 다른 모든 답변은 유형의 크기, 유형의 상대적 크기 또는 표현에 대한 가정을합니다.
laindir

질문은 두 개의 부호있는 정수를 input으로 말하므로 모든 쌍에서 작동해야한다고 말하고 싶습니다. main(a,b)이미 정의되지 않은 동작이므로 어떤 대답도 작동하지 않을 수 있습니다. 이식성을 신경 쓰지 마십시오.
Dennis

정의되지 않은 동작에 관해서는 옳습니다. 따라서 내 구현은 실제로 표준에 의해 아무것도 보장하지 않습니다. 제한 사항을 나타내는 메모를 추가하겠습니다.
laindir

4

 59    54 자

gcc와 같은 컴파일러를 사용하는 54 개의 문자 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);}

산출:

  • x <y 인 경우 ASCII 코드 0x00
  • x> y 인 경우 ASCII 코드 0xFF
  • x == y 인 경우 ASCII 코드 0x01

1
main(x,y)gcc 에서 작동하므로 문자 수에서 5 바이트를 자유롭게 떨어 뜨릴 수 있습니다.
Martin Ender

main (x, y)가 내 gcc에서 작동하지 않습니다. 컴파일러 옵션이 필요할 수 있습니다. 그러나 main (x, y)를 x; main (y)로 바꿀 수 있습니다.
Florian F

3

66102 바이트

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 비트 정수에 맞지 않는 너무 큰 차이에도 작동합니다. 나는 약간의 비트 마법으로 중첩 된 삼항을 단축 할 수 있다고 확신합니다.


내가 틀렸다면 정정하되, 내 삼항에 a <0이 표시됩니다.
overactor

@overactor fixed
Martin Ender

3

52 바이트

슬프게도 이것은 양의 정수에서만 작동하지만 순수 산술 연산자를 사용하는 개념이 흥미 로웠다고 생각했습니다.

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

출력 :

  • ASCII 코드 0xFF : b 미만
  • ASCII 코드 0x00 : a와 b
  • ASCII 코드 0x01 : a보다 큼

양의 정수에만 사용 putchar(a/b-b/a)하는 경우 훨씬 짧습니다.
Dennis

예를 들어 (50,1) 및 (51,1)에 대해 다른 출력을 생성하는 @Dennis. 그러나 나는 조금 단축 할 수있었습니다.
Digital Trauma

1
예, 제대로 생각하지 못했습니다 ...
Dennis

2

66 바이트

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

바이트 0x00 if a == b, 0x01 if a < b및 0xff if를 인쇄합니다 a > b.

이후 [내] 프로그램에서 비 ASCII 또는 비 인쇄 가능한 ASCII 문자아무것도 명시 적으로 질문에 금지되지 않은 경우, 다음이 허용 의에서 인쇄 할 수없는 문자 출력은 완전히 잘해야한다.


이전 버전에서는 오버플로를 잘 처리하지 못했습니다. 이것은 long64 비트 인 x64 Linux에서 작동합니다 .
Dennis

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로 변환

부호가 아닌 상위 비트를 데이터로 처리하기 위해 나누기를 부호없는 것으로 캐스팅

^를 XOR a와 b를 사용하여 같으면 0을 반환합니다.

중첩 조건부 (?)를 사용하여 "<", ">"또는 "="를 가져와 puts ()에 피드


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

이것은 a와 b에 1<<31( INT_MIN)를 추가하여 시작 하므로 0은 이제 INT_MIN. 그런 다음 각 루프가 0이 될 때까지 루프마다 a와 b를 감소시키고 감소시킨 다음 a, b 또는 둘 다 0인지에 따라 0, 1 또는 2를 인쇄합니다.

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있는지 테스트 만합니다. 당신은 필요합니다 . ab&&
데니스

@Dennis, 그렇습니다, 감사합니다.
과잉 행위자

1

짧은 코드 작성조차 시도하지 않을 것이라고 생각합니다. 내가 시도 할 것은 C99 사양에 따라 이식 가능한 방식 으로이 비교를 수행하는 것입니다.

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

모듈로 연산자는 부호를 유지하지만 0을 생성 할 수 있습니다 (음수 0 포함). 따라서 검사 할 홀수 값과 짝수 값을 모두 보장합니다 (1의 보수 사용 여부를 모르더라도). 산술 연산이 오버플로 될 수 있지만 비트 단위는 그렇지 않습니다. 비트가 설정되고 지워지도록하여 실수로 숫자를 음의 0 또는 트랩 값으로 변환하지 않도록합니다. 가능한 트랩 표현으로 lvalue를 넣을 때까지 정의되지 않은 동작을 유발하지 않기 때문에 두 가지 작업이 이상하게 수행되어야한다는 사실은 중요하지 않습니다. 비트 0을 토글 한 상태에서 작업을 수행하면 정확히 하나의 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];
}

이 방법은 정수 음수 0의 부호를 추출 할 수있는 몇 가지 중 하나 일 수 있습니다. 우리는 명시 적으로 0을 확인하여 문제를 해결합니다. 우리가 실제 골프를한다면, 물론 0을 비교하여 빼기를 수행 할 수도 있습니다.


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

stdio.h가없는 64 자

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.