19
\$\begingroup\$

In C++, there exists a a <=> b three-way comparison operator that, for numerical types, does the following:

  • If a < b, then return a negative number.
  • If a = b, then return a (mathematically speaking) sign-less number.
  • If a > b, then return a positive number.

The Challenge

Implement the shortest full program, function, method, or custom operator such that, when given two numbers of the same type a and b,

  • If a < b, then return -1.
  • If a = b, then return 0.
  • If a > b, then return 1.

Notes

  • If you're writing in x86 assembly, this question may be of use to you.
  • This is , so shortest answer in bytes wins!
\$\endgroup\$
10
  • 1
    \$\begingroup\$ Do we have to handle all combinations of inputs? (I.e. can we assume that a - b will yield the arithmetic result, even when a is the lowest representable value and b is the highest?) \$\endgroup\$ Mar 20 at 13:15
  • 1
    \$\begingroup\$ @TobySpeight You will need to handle all combinations of inputs. \$\endgroup\$
    – bigyihsuan
    Mar 20 at 13:22
  • 5
    \$\begingroup\$ Note that the C++ 3-way comparison is actually "compares equal to 0" and "compares less than 0" and "compares greater than 0". 1 and -1 are explicitly not required, by design, unlike your ask. I only mention this because your first paragraphs are not true. \$\endgroup\$
    – Yakk
    Mar 21 at 14:57
  • 1
    \$\begingroup\$ If a language has support for multiple numeric types, such as integers and floating point numbers, does it need to support all of them? Basically every solution using subtraction and supporting floating point numbers doesn't work. \$\endgroup\$
    – Tyilo
    Mar 22 at 9:47
  • 2
    \$\begingroup\$ @Tyilo the original draft of this challenge in sandbox had a bonus for supporting multiple numeric types, but was cut because "bonuses are bad". Pick whichever numeric type leads to the shortest solution. \$\endgroup\$
    – bigyihsuan
    Mar 22 at 13:04

56 Answers 56

8
\$\begingroup\$

BQN, 2 bytes

×-

Try it at BQN REPL

×       # sign of
 -      # left arg minus right arg

BQN, 3 bytes

<->

Try it at BQN REPL

This clearly isn't the shortest possible solution in BQN (see above), but it is particularly visually appealing due to its similarity to the C++/Perl/etc <=> operator.

<->     # 3-element train abc 
        # ( x abc y expands to: (x a y) b (x c y) )
<       # left arg < right arg
 -      # minus
  >     # left arg > right arg 

(a similar 'reverse-comparison' operator - >-< is also possible and also [I think] looks nice)

\$\endgroup\$
5
  • 3
    \$\begingroup\$ Polyglots with Dyalog APL too \$\endgroup\$
    – Seggan
    Mar 20 at 12:37
  • 1
    \$\begingroup\$ Does this handle overflows? \$\endgroup\$ Mar 21 at 6:16
  • 2
    \$\begingroup\$ @MooingDuck - Yes and yes. The first one is helped by BQN's representation of overflowing-numbers as infinity (type 1e1000 into the REPL to see); the second one only needs to compare two booleans so doesn't have a problem. \$\endgroup\$ Mar 21 at 7:53
  • \$\begingroup\$ Isn't what you call "reverse-comparison" operator actually the correct answer to this question, and not the other one? \$\endgroup\$
    – wimi
    Mar 22 at 9:22
  • \$\begingroup\$ @wimi - Hm - I think you're right (that >-< and not <-> is equivalent to <=>). The question itself just states that we are 'given two numbers', without specifying the order, but I agree that they're the wrong way around... That's a pity \$\endgroup\$ Mar 22 at 11:25
8
\$\begingroup\$

polyglot, 3 bytes

<=>

Try it in Perl!

<Insert other languages that already have the exact <=> operator here>

\$\endgroup\$
5
  • \$\begingroup\$ is this valid? it's not a function, after all... \$\endgroup\$
    – ASCII-only
    Mar 20 at 11:39
  • \$\begingroup\$ I don't know, really. The challenge reads "Implement the shortest full program, function, method, or custom operator...". It's an operator. Obviously it isn't custom, because it's a built-in, and for the same reason I didn't implement it myself, but otherwise it seems Ok... \$\endgroup\$ Mar 20 at 11:42
  • 2
    \$\begingroup\$ ah, didn't see the part about custom operators being explicitly allowed... but yeah it does still feel on the line \$\endgroup\$
    – ASCII-only
    Mar 20 at 11:55
  • 1
    \$\begingroup\$ I'm not sure, since the OP speaks of C++, where you can define custom operators, and asks us to implement it.. simply inserting the operator you chose in an answer would not do, the code should implement it \$\endgroup\$
    – Kaddath
    Mar 22 at 14:41
  • 1
    \$\begingroup\$ @Kaddath - I agree with you, but currently I count at least 8 built-in answers (Python 2, Java, 05AB1E, etc) that don't implement anything. That's why I feel it's appropriate to put all the boring built-ins together into a 'community wiki' answer... \$\endgroup\$ Mar 22 at 16:08
7
\$\begingroup\$

Python 2, 3 bytes

cmp

A built-in function that accepts \$a\$ and \$b\$ and returns \$a \lt = \gt b\$.

Try it online!

\$\endgroup\$
6
\$\begingroup\$

JavaScript (ES6), 17 bytes

Expects (a)(b).

a=>b=>(a>b)-(a<b)

Try it online!

\$\endgroup\$
2
  • \$\begingroup\$ 3 bytes can be cut down by using Math.sign(a-b) \$\endgroup\$
    – cdm
    Mar 21 at 16:52
  • 1
    \$\begingroup\$ @cmd We would still need to take a and b as input, for a total of +3 bytes. (If we had a Math.cmp builtin taking 2 arguments, then the answer would be just Math.cmp.) \$\endgroup\$
    – Arnauld
    Mar 21 at 16:55
5
\$\begingroup\$

Python 3, 22 bytes

lambda a,b:(a>b)-(a<b)

Try it online!

Python 3 lacks the builtin cmp

-1 thanks to Dominic van Essen

\$\endgroup\$
2
  • 8
    \$\begingroup\$ Surely lambda a,b:(a>b)-(a<b) is only 22...? \$\endgroup\$ Mar 20 at 8:57
  • \$\begingroup\$ @DominicvanEssen Of course! \$\endgroup\$
    – Jitse
    Mar 20 at 9:17
4
\$\begingroup\$

Vyxal, 2 bytes

Try it Online!

Takes input as b then a. Simply subtract the two numbers and get the sign of the result.

Alternatively a more fun looking, symbol only answer comes in at 17 bytes:

Vyxal, 17 bytes

-:::-<[::-$~-|:]/

Try it Online!

Also takes b then a. This answer is purely just for fun, and could be made shorter by using numbers and letters (-D0<[N|:]/).

Explained

-:::-<[::-$~-|:]/
-:                # Subtract the two numbers and push a copy
  ::-             # Push 0 to the stack by subtracting the top of the stack from itself
     <            # Is the original top of the stack < 0?
      [           # If so:
       ::         #   Duplicate the top of the stack twice. This could just be `D`, but that wouldn't be a symbol.
         -        #   Subtract those copies to get 0 again.
          $~-     #   Push the 0 under the top of the stack, and subtract without popping. The stack is now [0, a - b, -(a - b)]
             |    # Otherwise:
              :   #   Just duplicate the top of the stack
               ]  # this whole if statement was to make sure there was [a - b, abs(a - b)] as the stack
                / # Divide the top two stack items to get either -1, 0 or 1. negative/positive = -1, 0/0 = 0 and positive/positive = 1
\$\endgroup\$
1
  • \$\begingroup\$ -:ȧ/ or ₌><- for a non builtin \$\endgroup\$
    – naffetS
    Mar 22 at 3:49
4
\$\begingroup\$

Java (JDK), 14 bytes

Float::compare

Try it online!

Java (JDK), 13 bytes

Long::compare

Try it online!

Only supports integers.

\$\endgroup\$
7
  • 8
    \$\begingroup\$ For a more general solution: Comparable::compareTo (not golfier but felt like sticking this in a comment) \$\endgroup\$
    – Seggan
    Mar 20 at 1:40
  • \$\begingroup\$ This answer does not satisfy the question. Float.compare() returns a positive, zero, or negative number to indicate ordering, not +1, 0, -1. The problem is that the question is more restrictive than what programming languages actually prescribe. \$\endgroup\$
    – Nayuki
    Mar 21 at 15:28
  • 2
    \$\begingroup\$ @Nayuki Did you try testing the code through the TIO link in my answer? It never returns anything other than -1, 0, or 1. On Code Golf, "a programming language is defined by its implementation". My code works on this implementation (always giving the correct outputs), so it is a valid submission. \$\endgroup\$ Mar 21 at 16:35
  • \$\begingroup\$ Most implementations do return -1, 0, or 1 for the static compare methods. (In fact, it'd be strange to have an implementation not return one of those, as that doesn't make it any easier to implement.) For example, you can see OpenJDK's source for Float here: github.com/openjdk-mirror/jdk7u-jdk/blob/master/src/share/… \$\endgroup\$ Mar 21 at 16:36
  • 2
    \$\begingroup\$ @Nayuki That doesn't matter. The consensus is that languages are defined by implementation, not specification. See codegolf.meta.stackexchange.com/questions/7832/…, codegolf.meta.stackexchange.com/a/14339/99986. So it's perfectly valid to rely on undefined or implementation-dependent behavior. See codegolf.meta.stackexchange.com/questions/5486/… as well as the comments there. \$\endgroup\$ Mar 21 at 17:07
4
\$\begingroup\$

Excel, 12 bytes

=SIGN(A1-B1)

where A1 and B1 contain a and b respectively.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ This does not appear to handle overflows \$\endgroup\$ Mar 21 at 6:17
4
\$\begingroup\$

Nibbles, 1.5 bytes (3 nibbles)

`$-
`$-         # full program
`$-$@       # with implicit args shown;
`$          # get sign of
   $        # arg1
  -         # minus
    @       # arg2

enter image description here

\$\endgroup\$
4
\$\begingroup\$

K (ngn/k), 9 bytes

1&-_1^-%-

Try it online!

K lacks a sign builtin, which makes this a bit trickier.

-%- negative square root of a-b. This is negative if a>b, zero if a=b and -0n (negative null value) if a<b.
1^ Replace null with 1.
-_ floor and negate the number. In combination with the earlier - this does a ceil on the square root.
1& take the minimum of 1 and this number.

If the input was restricted to integers, 0 1' would calculate the sign, leading to 0 1'- as a full solution.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ If the input was restricted to integers, you could also do 1&-1|-... \$\endgroup\$
    – naffetS
    Mar 22 at 3:47
4
\$\begingroup\$

Go, 52 51 bytes

func(a,b int)int{n:=1
for-1<n&&b-a<n{n--}
return-n}

Attempt This Online!

By @Kevin Cruijssen. Uses a for loop to get the return value rather than a chain of ifs.

Changelog

  • -1 by @naffetS

Old answer, 56 bytes

func(a,b int)int{n:=0
if a>b{n=1}
if a<b{n=-1}
return n}

Attempt This Online!

Go doesn't have any sort of built-in abs like C, or default type methods like Java, so a function it is. Go also doesn't have ternary expressions, so the old-school "set and check" pattern is needed.

\$\endgroup\$
5
  • 1
    \$\begingroup\$ Wow, this seems really long! I don't speak GO, but can't you at least save a few bytes like this? \$\endgroup\$ Mar 20 at 13:50
  • \$\begingroup\$ Or even like this...? \$\endgroup\$ Mar 20 at 14:01
  • \$\begingroup\$ Yeah, the else was real obvious and somehow I missed that lol. \$\endgroup\$
    – bigyihsuan
    Mar 20 at 14:01
  • 2
    \$\begingroup\$ 52 bytes \$\endgroup\$ Mar 20 at 14:19
  • 1
    \$\begingroup\$ -1 \$\endgroup\$
    – naffetS
    Mar 22 at 3:52
4
\$\begingroup\$

J, 3 bytes

*@-

Try it online! The 3-byte solution >-< featured in a few other answers also works for the same byte count (greater-than minus less-than).

Works for any numeric type. Anonymous dyad.

Explanation

*@-
*     sign
 @    of
  -   difference
\$\endgroup\$
6
  • \$\begingroup\$ Looks like a dyad to me. \$\endgroup\$
    – south
    Mar 21 at 1:19
  • 1
    \$\begingroup\$ @south Right you are! Heavens know why I said monad lol \$\endgroup\$ Mar 21 at 2:49
  • \$\begingroup\$ Outputs the wrong answer for (-1e308, -1e308) => _1 and (-1e308, 1e308) => 0 \$\endgroup\$
    – Tyilo
    Mar 22 at 9:45
  • 1
    \$\begingroup\$ @Tyilo OP clarified that we can pick whichever type works for the golf. The numbers you provided are floating point numbers. I pick the integer type, which you will note my solution works well for. If you insist on numbers so large, you can use the extended type: (-10^308x) f (-10^308x) outputs 0 as expected. \$\endgroup\$ Mar 22 at 17:17
  • 1
    \$\begingroup\$ @Tyilo I suppose, fair enough! Just shows it works so long as the input isn't deviously crafted :) \$\endgroup\$ Mar 23 at 4:12
4
\$\begingroup\$

Raku, 8 bytes

+(*cmp*)

Try it online!

cmp is Raku's built-in smart comparison operator, and *cmp* is an anonymous function that passes its arguments to that operator.

Unfortunately for this challenge, cmp doesn't return -1, 1, or 0, but one of the enumerated values Less, More, or Same, so the prefix + operator converts those values into their integer values.

The non-golfy solution would be to just compose the two operators:

&prefix:<+> o &[cmp]
\$\endgroup\$
2
  • \$\begingroup\$ can use cmp to not write the space \$\endgroup\$ Mar 21 at 14:02
  • 1
    \$\begingroup\$ @MustafaAydın Huh! I assumed cmp was the stringwise version of <=> as in Perl 5, but it's smarter than that. Thanks! \$\endgroup\$
    – Sean
    Mar 24 at 20:09
3
\$\begingroup\$

Kotlin, 16 bytes

Float::compareTo

Try it online!

Annoyingly, longer than Java.

Kotlin, 14 bytes

Int::compareTo

Try it online!

Works only on ints (I edited this after seeing that Java got edited).

\$\endgroup\$
3
\$\begingroup\$

R, 15 bytes

\(a,b)sign(a-b)

Attempt This Online!

\$\endgroup\$
1
  • 2
    \$\begingroup\$ It would have been cooler if you'd made it inline as %<=>%, though... \$\endgroup\$ Mar 20 at 7:35
3
\$\begingroup\$

05AB1E, 2 bytes

.S

Builtin. Takes the inputs in the order \$b,a\$.

Try it online.

Explanation:

.S  # Compare the second (implicit) input-integer `a` with the first (implicit)
    # input-integer `b`, and push -1 if a<b; 0 if a==b; or 1 if a>b
    # (which is output implicitly as result)
\$\endgroup\$
3
\$\begingroup\$

HP‑41C series,  9  11 Bytes

a needs to be entered first, then b, so a is placed in the Y register and b in the X register.

01♦LBL⸆S     5 Bytes    global label requires 4 + m Bytes
02 SF 24     2 Bytes    ignore “out of range” errors, and instead
                        return ±9.999999999E99 as an approximation
03 −         1 Byte     X ≔ Y − X
04 X≠0?      1 Byte     if X = 0 then skip next line
05 SIGN      1 Byte     ↯ `SIGN` returns `1` for zero
06 RTN       1 Byte     `RTN` does not affect local label search
\$\endgroup\$
1
  • \$\begingroup\$ Does work also on the Free42 calculator \$\endgroup\$
    – Satoshi
    Mar 21 at 10:17
3
\$\begingroup\$

Golfscript, 7 bytes

.~>\~<-

read from stdin

# explanation:
. # duplicate
~ # unpack
> # gt 
\ # store the result and get duplicated stdin again
~ # unpack
< # lt
- # gt-lt
\$\endgroup\$
1
  • \$\begingroup\$ Welcome to Code Golf! \$\endgroup\$ Mar 21 at 22:23
3
\$\begingroup\$

Burlesque, 2 bytes

cm

Try it online!

Built in compare.

\$\endgroup\$
3
\$\begingroup\$

PIC16F88x Machine Code, 6 words (84 bits)

A function that expects a to be at address 0x70 in memory, and b to be in register W. Returns the result in register W.

The PIC16 uses 14-bit instruction words. Because the number of words is even, this function can be represented exactly in hex with no padding:

0bc1d03d001ff0dfff401

In mpasm syntax, that is:

    SUBWF 0x70,F   ; Subtract W from the value at 0x70. Leave the result at
                   ; 0x70.
    BTFSC STATUS,2 ; Check the zero flag (bit 2 of the STATUS register) and skip
                   ; the next instruction if it's not set.
    RETLW 0x00     ; Set the W register to 0 and return.
    BTFSC 0x70,7   ; Skip the next instruction if the MSb of the value at 0x70
                   ; is 0 (i.e. the result of subtraction is positive).
    RETLW 0xFF     ; Set the W register to 0xff (-1) and return.
    RETLW 0x01     ; Set the W register to 1 and return.

Bit for bit, this is encoded as:

00 0010 1111 0000
00 0010           SUBWF
         111 0000       0x70
        1                    F

01 1101 0000 0011
01 11             BTFSC
         000 0011       STATUS
     01 0                      2

11 0100 0000 0000
11 01             RETLW
        0000 0000       0x00
     00                      (ignored)

01 1111 1111 0000
01 11             BTFSC
         111 0000       0x70
     11 1                    7

11 0111 1111 1111
11 01             RETLW
        1111 1111       0xff
     11                      (ignored)

11 0100 0000 0001
11 01             RETLW
        0000 0001       0x01
     00                      (ignored)

The PIC16F88x family of microcontrollers have four memory banks of 128 bytes each. (These are actually bytes this time, and not 14-bit words.) Which one is used depends on the value of the STATUS register. However, addresses 0x70 through 0x7f are the same on all banks, so by placing the operands there the function doesn't have to change banks to access them. I'm not aware of any standard calling convention as far as argument location goes, but the return value being in register W is standard (hence the existence of the RETLW instruction).

\$\endgroup\$
3
\$\begingroup\$

K (ngn/k), 5 bytes

-/<?,

Try it online!

  • , concatenate the inputs
  • <? grade-up the distinct-ified result from above; if the first value is smaller than the second, the result will be 0 1; if larger, 1 0, if the same, ,0
  • -/ run a minus-reduce and (implicitly) return

An alternative version that takes the input as a list of two numbers is -/<?:.

\$\endgroup\$
1
  • \$\begingroup\$ Aah, how did I miss this? Only had the APLcart version ({⊃(⍋-⍒)⍺⍵}) in mind, which would've been too long because of the two grades \$\endgroup\$
    – ovs
    Mar 24 at 6:55
2
\$\begingroup\$

Pascal, 55 Bytes

function f(a,b:real):real;begin f:=ord(a>b)-ord(a<b)end
\$\endgroup\$
2
\$\begingroup\$

Retina 0.8.2, 29 bytes

\d+
$*
(1*) \1
0
1+0
1
01+
-1

Try it online! Link includes test cases. Only works on non-negative integers. Explanation:

\d+
$*

Convert to unary.

(1*) \1
0

Try to subtract; this will leave 0 if a = b.

1+0
1

If a > b then replace the result with 1.

01+
-1

If a < b then replace the result with -1.

\$\endgroup\$
2
\$\begingroup\$

Charcoal, 12 bytes

NθNηI⁻›θη‹θη

Try it online! Link is to verbose version of code. Explanation: Port of @Arnauld's JavaScript answer.

Alternative approach, also 12 bytes:

≔⁻NNθI÷θ∨↔θ¹

Try it online! Link is to verbose version of code. Explanation: Divides the difference between the numbers by the absolute value of the difference, or 1 if that's zero.

\$\endgroup\$
2
\$\begingroup\$

MathGolf, 2 bytes

Try it online.

Explanation:

,  # Subtract the second (implicit) input by the first (implicit) input: b-a
 σ # Get the sign of that (-1 if <0; 0 if ==0; 1 if >0)
   # (after which the entire stack is output implicitly as result)
\$\endgroup\$
2
\$\begingroup\$

C (gcc), 22 bytes

This is practically @TobySpeight's answer now since he changed the entire algorithm.

f(a,b){a=(a>b)-(a<b);}

Try it online!

\$\endgroup\$
2
  • \$\begingroup\$ The more usual implementation, a=(a>b)-(a<b) is not only 4 bytes shorter, but also correct for values where a-=b is undefined due to signed integer overflow. \$\endgroup\$ Mar 20 at 13:18
  • \$\begingroup\$ @TobySpeight I didn't think of that ... thanks :) \$\endgroup\$
    – Peter
    Mar 20 at 13:37
2
\$\begingroup\$

Pip, 4 bytes

aCMb

There's a built-in operator for that. (Fun fact: in my original designs for Pip, this operator was <=>, until I realized that having a 3-character operator in a golfing language was silly.)

Attempt This Online!

\$\endgroup\$
2
\$\begingroup\$

Pyth, 3 bytes

._-

Try it online!

Defines a function which takes two inputs b, a.

Explanation

  -    # subtract the second argument from the first
._     # take the sign
\$\endgroup\$
1
  • 1
    \$\begingroup\$ It makes an emoticon :D \$\endgroup\$
    – Joao-3
    Mar 24 at 19:46
2
\$\begingroup\$

Julia 1.0, 13 3 bytes

cmp

Try it online!

-10 bytes thanks to MarcMush: use cmp

Alternate solution, 13 bytes

a%b=sign(a-b)

Try it online!

Alternate solution (15 bytes)

a%b=(a>b)-(a<b)

Try it online!

Some operators have lower precedence than < and >. Redefining one of them as - removes the need for parentheses but doesn't save bytes overall:

~=-
a%b=a>b~a<b

Try it online!

\$\endgroup\$
2
  • 1
    \$\begingroup\$ 3 bytes : cmp \$\endgroup\$
    – MarcMush
    Mar 21 at 18:41
  • \$\begingroup\$ Good catch! I've added your solution here, but it probably deserves its own answer. \$\endgroup\$ Mar 21 at 19:38
2
\$\begingroup\$

Piet + ascii-piet, 21 bytes (4×7=28 codels)

vekabrA krbtkFbks?Tbb

Try Piet online!

Just a minor variation from my answer to "output the sign". Takes two numbers and subtracts instead of taking just one number, and then the rest follows the same logic.

A1->A4
inN inN -    [a-b] Take two numbers and subtract
A4->A7->B7->B5
dup 1 ! > !  [a-b a-b<=0]
CC+          [a-b] Continue on row B if a-b<=0, shift to row C otherwise
B5->B2
! 1 -        [(a-b==0)-1] -1 if a-b!=0 (which implies a-b<0), 0 otherwise
C5->C2
1            [a-b 1] Ignore the previous number and push 1
C2->C1
outN         Print the top number and exit
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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