12
\$\begingroup\$

Produce the shortest program which takes two signed integers as input (through stdin or as arguments) and displays 3 different outputs depending upon whether the first number is (1) greater than, (2) smaller than, or (3) equal to the second number.

The Catch

You cannot use any of the following in your program:

  • The standard comparison operators: <, >, <=, >=, ==, !=.
  • Any library file apart from conio, stdio, or iostream.
  • Any non-ASCII or non-printable ASCII character.

The Winner

The program with the shortest number of characters wins.

\$\endgroup\$
  • \$\begingroup\$ I suppose using things like abs without including the library file (because the compiler knows it anyway) isn't allowed either? \$\endgroup\$ – Martin Ender Sep 8 '14 at 11:10
  • 1
    \$\begingroup\$ @MartinBüttner yes, that would be a correct assumption. :) \$\endgroup\$ – grove Sep 8 '14 at 11:16
  • 5
    \$\begingroup\$ Why the restriction to C(++)? If it's because you want answers to be portable despite the unportability of C's basic types then you should state that. If it's an arbitrary restriction then you should be aware that arbitrary restrictions to one language are unpopular on this site. \$\endgroup\$ – Peter Taylor Sep 8 '14 at 11:35
  • 8
    \$\begingroup\$ @PeterTaylor it's part of the challenge. It would be a very different ballgame altogether if the question was language-agnostic. Restricting it to C/C++ changes the strategies used when approaching the problem. I recognize the need for questions to be open to most languages to promote participation by more people, but in this particular problem the restriction to C/C++ and their specific operators and methods is an integral part of the challenge. \$\endgroup\$ – grove Sep 8 '14 at 11:44
  • 1
    \$\begingroup\$ @EvilTeach yes; if anything is not explicitly forbidden in the question, then it is permitted. \$\endgroup\$ – grove Sep 8 '14 at 14:17

15 Answers 15

2
\$\begingroup\$

53 bytes

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

Only the first character of the output is relevant. The three different outputs are:

  1. '-' if b > a
  2. '0' if a == b
  3. any other character if a > b

It works for the full input range of int on all platforms where sizeof(long) > sizeof(int).

Edit: it costs one extra character to make case 3 print a '+' uniquely instead:

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

Maybe I'm missing something in the rules, but...

81 bytes

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

Ouputs 00 if a > b, -10 if a == b, and -1-1 if a < b.

\$\endgroup\$
  • \$\begingroup\$ As common as this sort of code is, C doesn't guarantee it works. long long could be more than 64 bits, int could be as large so you could overflow, the result of right shifting negative values is implementation defined. Pretty much all C-derived answers have similar issues. \$\endgroup\$ – Yann Vernier Sep 11 '14 at 11:45
  • 1
    \$\begingroup\$ @YannVernier: Understood. I'm guessing a 100% foolproof solution would be a monster, since the only thing we could do safely (i.e. without shifting or overflow) is bit twiddling, and to do that safely we'd need to determine the length of the operands using sizeof. \$\endgroup\$ – COTO Sep 11 '14 at 13:32
6
\$\begingroup\$

90 bytes

If we can use stdio, why not use its formatting capabilities to perform comparison?

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

Assumes ASCII-compatible encoding and little-endianness.

72 bytes

Quotients are rounded toward zero but right-shifts are (in practice) "rounded down". That's a dead giveaway.

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

65 79 bytes

Another distinguishing property of negative numbers is that they produce negative modulo. This one doesn't depend on integer representation at all; it even works on my 8-bit excess-127 toaster! Oh, and since we can use conio, why not save two bytes with putch? Now, if I could only find my copy of 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);}

EDIT: Handle large differences assuming long long is wider than int.

\$\endgroup\$
  • \$\begingroup\$ I'm pretty sure you need a delimiter between the %ds in your scanf to unambiguously parse two integers. Nice idea though! \$\endgroup\$ – Martin Ender Sep 8 '14 at 12:35
  • 1
    \$\begingroup\$ @Martin: Well, it works with GCC, but I'm really not sure if it's bona fide. \$\endgroup\$ – Ell Sep 8 '14 at 12:41
  • \$\begingroup\$ What I mean is, how do you distinguish between inputs a = 1, b = 23 and a = 12, b = 3. Wouldn't you need to put 123 on STDIN in either case? \$\endgroup\$ – Martin Ender Sep 8 '14 at 12:43
  • 1
    \$\begingroup\$ Like I said, it seems to work (with 1 23 and 12 3 as inputs). \$\endgroup\$ – Ell Sep 8 '14 at 12:46
  • 2
    \$\begingroup\$ Ohhh, you do include spaces in the input. Yeah I'm not surprised that works, actually. \$\endgroup\$ – Martin Ender Sep 8 '14 at 12:46
5
\$\begingroup\$

64 61 characters

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.

\$\endgroup\$
  • \$\begingroup\$ This won't work if a-b overflows. \$\endgroup\$ – Dennis Sep 9 '14 at 1:05
  • \$\begingroup\$ Sadly that is true, but I could not think of any platform agnostic way to avoid this without comparison operators. The question does not specify a range of inputs for which results must be valid. This answer is guaranteed by the standard to work for all inputs between -(2^14) and 2^14 - 1 on all compliant platforms, and it will probably work for a substantially larger range on most platforms. All the other answers at this point make assumptions about size of type, relative sizes of types, or representation. \$\endgroup\$ – laindir Sep 9 '14 at 14:31
  • \$\begingroup\$ 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. \$\endgroup\$ – Dennis Sep 9 '14 at 14:55
  • \$\begingroup\$ 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. \$\endgroup\$ – laindir Sep 9 '14 at 17:25
3
\$\begingroup\$

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.

\$\endgroup\$
  • \$\begingroup\$ Correct me if I'm wrong, but I'm seeing a<0 in your inner ternary. \$\endgroup\$ – overactor Sep 8 '14 at 11:21
  • \$\begingroup\$ @overactor fixed \$\endgroup\$ – Martin Ender Sep 8 '14 at 11:26
3
\$\begingroup\$

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
\$\endgroup\$
  • \$\begingroup\$ If you're going only for positive integers, putchar(a/b-b/a) is a lot shorter. \$\endgroup\$ – Dennis Sep 8 '14 at 19:46
  • \$\begingroup\$ @Dennis that produces different outputs for example for (50,1) and (51,1). But I was able to shorten a bit though. \$\endgroup\$ – Digital Trauma Sep 8 '14 at 19:51
  • 1
    \$\begingroup\$ Yes, wasn't thinking properly... \$\endgroup\$ – Dennis Sep 8 '14 at 19:53
3
\$\begingroup\$

 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
\$\endgroup\$
  • 1
    \$\begingroup\$ I can assure you, main(x,y) works in gcc, so feel free to drop those 5 bytes from your character count. \$\endgroup\$ – Martin Ender Sep 9 '14 at 9:37
  • \$\begingroup\$ 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). \$\endgroup\$ – Florian F Sep 11 '14 at 19:36
2
\$\begingroup\$

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.

\$\endgroup\$
  • \$\begingroup\$ My previous version didn't handle overflow very well. This works on x64 Linux, where long is 64-bits. \$\endgroup\$ – Dennis Sep 8 '14 at 19:41
2
\$\begingroup\$

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()

\$\endgroup\$
1
\$\begingroup\$

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

\$\endgroup\$
  • \$\begingroup\$ 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. \$\endgroup\$ – Martin Ender Sep 8 '14 at 14:01
  • \$\begingroup\$ Assignment has a lower precedence than the ternary operator: en.cppreference.com/w/c/language/operator_precedence \$\endgroup\$ – Martin Ender Sep 8 '14 at 14:08
  • \$\begingroup\$ 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. \$\endgroup\$ – COTO Sep 8 '14 at 14:15
1
\$\begingroup\$

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.

\$\endgroup\$
  • 1
    \$\begingroup\$ This won't work if a-b overflows. \$\endgroup\$ – Dennis Sep 9 '14 at 1:07
1
\$\begingroup\$

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.

\$\endgroup\$
  • \$\begingroup\$ I can't test my solutions for the moment, so feel free to point out mistakes. \$\endgroup\$ – overactor Sep 8 '14 at 13:35
  • \$\begingroup\$ 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 &&. \$\endgroup\$ – Dennis Sep 9 '14 at 4:38
  • \$\begingroup\$ @Dennis, you're right, thanks. \$\endgroup\$ – overactor Sep 9 '14 at 5:05
1
\$\begingroup\$

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.

\$\endgroup\$
1
\$\begingroup\$

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

\$\endgroup\$
1
\$\begingroup\$

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) ? ">" : "=");
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.