Compare two integers in C or C++ without comparison operators

12

2

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.

grove

Posted 2014-09-08T10:58:14.413

Reputation: 139

I suppose using things like abs without including the library file (because the compiler knows it anyway) isn't allowed either? – Martin Ender – 2014-09-08T11:10:40.897

1@MartinBüttner yes, that would be a correct assumption. :) – grove – 2014-09-08T11:16:38.027

5Why 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. – Peter Taylor – 2014-09-08T11:35:16.263

8@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. – grove – 2014-09-08T11:44:15.110

Is the ternary operator allowed? – EvilTeach – 2014-09-08T14:03:41.130

1@EvilTeach yes; if anything is not explicitly forbidden in the question, then it is permitted. – grove – 2014-09-08T14:17:19.613

Answers

2

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

paradigmsort

Posted 2014-09-08T10:58:14.413

Reputation: 66

6

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.

Ell

Posted 2014-09-08T10:58:14.413

Reputation: 7 317

I'm pretty sure you need a delimiter between the %ds in your scanf to unambiguously parse two integers. Nice idea though! – Martin Ender – 2014-09-08T12:35:57.663

1@Martin: Well, it works with GCC, but I'm really not sure if it's bona fide. – Ell – 2014-09-08T12:41:30.293

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? – Martin Ender – 2014-09-08T12:43:47.653

1Like I said, it seems to work (with 1 23 and 12 3 as inputs). – Ell – 2014-09-08T12:46:17.703

2Ohhh, you do include spaces in the input. Yeah I'm not surprised that works, actually. – Martin Ender – 2014-09-08T12:46:56.837

6

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.

COTO

Posted 2014-09-08T10:58:14.413

Reputation: 3 701

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. – Yann Vernier – 2014-09-11T11:45:43.653

1@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. – COTO – 2014-09-11T13:32:38.097

5

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.

laindir

Posted 2014-09-08T10:58:14.413

Reputation: 341

This won't work if a-b overflows. – Dennis – 2014-09-09T01:05:59.507

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. – laindir – 2014-09-09T14:31:07.467

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 – 2014-09-09T14:55:20.653

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 – 2014-09-09T17:25:56.880

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.

Martin Ender

Posted 2014-09-08T10:58:14.413

Reputation: 184 808

Correct me if I'm wrong, but I'm seeing a<0 in your inner ternary. – overactor – 2014-09-08T11:21:00.950

@overactor fixed – Martin Ender – 2014-09-08T11:26:18.187

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

Digital Trauma

Posted 2014-09-08T10:58:14.413

Reputation: 64 644

If you're going only for positive integers, putchar(a/b-b/a) is a lot shorter. – Dennis – 2014-09-08T19:46:31.800

@Dennis that produces different outputs for example for (50,1) and (51,1). But I was able to shorten a bit though. – Digital Trauma – 2014-09-08T19:51:36.240

1Yes, wasn't thinking properly... – Dennis – 2014-09-08T19:53:27.127

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

Todd Lehman

Posted 2014-09-08T10:58:14.413

Reputation: 1 723

1I can assure you, main(x,y) works in gcc, so feel free to drop those 5 bytes from your character count. – Martin Ender – 2014-09-09T09:37:14.923

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 – 2014-09-11T19:36:11.563

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.

Dennis

Posted 2014-09-08T10:58:14.413

Reputation: 196 637

My previous version didn't handle overflow very well. This works on x64 Linux, where long is 64-bits. – Dennis – 2014-09-08T19:41:30.927

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

Pelle

Posted 2014-09-08T10:58:14.413

Reputation: 201

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

ViralTaco_

Posted 2014-09-08T10:58:14.413

Reputation: 11

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.

overactor

Posted 2014-09-08T10:58:14.413

Reputation: 3 500

I can't test my solutions for the moment, so feel free to point out mistakes. – overactor – 2014-09-08T13:35:54.293

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 – 2014-09-09T04:38:37.040

@Dennis, you're right, thanks. – overactor – 2014-09-09T05:05:25.647

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

Michael M.

Posted 2014-09-08T10:58:14.413

Reputation: 12 173

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,50and51directly, instead of adding48`. – Martin Ender – 2014-09-08T14:01:26.580

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

– Martin Ender – 2014-09-08T14:08:47.653

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 – 2014-09-08T14:15:58.830

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.

CompuChip

Posted 2014-09-08T10:58:14.413

Reputation: 439

1This won't work if a-b overflows. – Dennis – 2014-09-09T01:07:42.670

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.

Yann Vernier

Posted 2014-09-08T10:58:14.413

Reputation: 131

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

Florian F

Posted 2014-09-08T10:58:14.413

Reputation: 591