Find the maximum of 3 numbers without branching

17

1

This time around your goal is to find the maximum of 3 integers (from -(2^31) to 2^31 - 1 in binary 2's complement) without using branching or loops.

You are only allowed to use

  • Inequality/Equality (==, >, >=, <, <=, !=) These count as 2 tokens.

  • Arithmetic (+, -, *, /)

  • Logical Operators (! not, && and, || or)

  • Bitwise Operators (~ not, & and, | or, ^ xor, <<, >>, >>> arithmetic and logical left and right shifts)

  • Constants. 0 tokens

  • Variable assignment. 0 tokens

Input 3 variables as a, b and c. Output the maximum number.

Standard atomic code-golf rules apply. If you have any questions please leave them in the comments. One token is any of the above with the special rules.

qwr

Posted 2014-06-25T00:03:09.363

Reputation: 8 929

ARM assembly has non-branching conditional instructions. Can I use those? – eaglgenes101 – 2017-12-01T15:27:22.743

What about defining an extra function? If this is allowed, how many tokens does it count as? – afuous – 2014-06-25T00:16:53.547

@voidpigeon You are only allowed to have one function, the one that takes the 3 inputs and outputs. – qwr – 2014-06-25T00:20:37.713

1

At first glance I thought, "we've had this before.", but I think comparators costing 2 changes the game quite a bit.

– primo – 2014-06-25T00:36:15.637

@primo I specifically asked for 3 inputs because it actually allows for some interesting improvements – qwr – 2014-06-25T00:39:06.877

Can the integers be repeated? eg: f(3,3,3)? And is integer division allowed? – Οurous – 2014-06-25T00:50:06.253

@Ourous Yes, just return or output the maximum. I'll allow integer division. – qwr – 2014-06-25T00:52:49.157

2Can we use inbuilt functions? – Registered User – 2014-06-25T04:44:24.813

Can we use : and ?? – Joshpbarron – 2014-06-26T07:44:38.650

@Joshpbarron, that would be branching – gnibbler – 2014-06-26T11:27:12.930

Answers

7

Javascript 10 tokens

Edit Using < and * instead of bit fiddling - as pointed out in comments, bits operations may fail for input near the range limit (over 30 bits)

function Max(x,y,z)
{
  var d=y-x;
  x=y-d*(d<0);
  d=x-z;
  return x-d*(d<0);
}

C 8 tokens

Language agnostic in fact, any C like language will do. To be picky, in standard C it's not portable because right shift may not extend the sign (but in common implementations it does).

In C (and C++, C#, and Java I think) we can easily handle overflow problems using bigger temporary values:

int Max(int x, int y, int z)
{
    long long X = x;
    long long Y = y;
    long long Z = z;
    long long D = Y-X;
    X=Y-((D>>63)&D);
    D=X-Z;
    return (int) (X-((D>>63)&D));
}

edc65

Posted 2014-06-25T00:03:09.363

Reputation: 31 086

1I'm being picky, but using C ints your code doesn't work for x=2147483647, y = -2, z=0. Your choice if you want to change it – qwr – 2014-06-25T00:48:10.433

10

Javascript

6 tokens

function maxOf3(a, b, c) {
    (b>a) && (a=b);
    (c>a) && (a=c);
    return a;
}

openorclose

Posted 2014-06-25T00:03:09.363

Reputation: 133

6+1 I see shortcut evaluation as a type of branching, but it's not forbidden in the rules – edc65 – 2014-06-25T01:33:46.820

11I would consider this as branching, haha – justhalf – 2014-06-25T02:52:07.690

2@edc65 It is. Allowing && and || was likely an oversight, which should be pointed out, rather than exploited. – primo – 2014-06-25T05:09:37.950

@primo This was an interesting issue. I believe some CISC architectures have instructions that include conditional statements, so I'm not sure how those would be counted. – qwr – 2014-06-25T05:54:21.187

2I guess it should be 4 tokens i.e 2 &&, < and >. The = is used as an assignment and counts as 0 – Clyde Lobo – 2014-06-25T12:40:27.063

@ClydeLobo It's 6 because < and > cost double. – Keen – 2014-06-25T17:02:05.923

6

C: 10 tokens

int max(int a, int b, int c)
{
    a += (b > a) * (b - a);
    a += (c > a) * (c - a);
    return a;
}

Inspired by @openorclose's answer, but converted to C and made branchless using multiplication rather than short circuit boolean operators.

Paul R

Posted 2014-06-25T00:03:09.363

Reputation: 2 893

3

Javascript

14 tokens

function max (a, b, c)
{
    var ab = (a >= b) * a + (a < b) * b;
    return (ab >= c) * ab + (ab < c) * c;
}

Fabricio

Posted 2014-06-25T00:03:09.363

Reputation: 1 605

1You are not allowed to create new functions – qwr – 2014-06-25T01:16:21.420

:( 14 tokens then – Fabricio – 2014-06-25T01:17:00.800

2

Many languages (Python) (10 tokens)

def max3(x,y,z):
    m = x ^ ((x ^ y) & -(x < y))
    return m ^ ((m ^ z) & -(m < z))

print max3(-1,-2,-3) # -1
print max3(-1,2,10) # 10

https://graphics.stanford.edu/~seander/bithacks.html#IntegerMinOrMax

Oh, someone already posted it :)

Mardoxx

Posted 2014-06-25T00:03:09.363

Reputation: 35

You are not allowed to create new functions – qwr – 2014-06-25T09:28:49.727

Ahh ok! Didn't read the comments :) – Mardoxx – 2014-06-25T10:24:08.593

@qwr I don't get it, you said: You are only allowed to have one function, the one that takes the 3 inputs and outputs. That's exactly what this answer has. The 2 prints are just test cases – Cruncher – 2014-06-25T14:40:54.337

1@Cruncher I edited the answer I did max2(max2(x,y),z) initially :) – Mardoxx – 2014-06-25T15:02:46.080

@Mardoxx ah. Well +1 – Cruncher – 2014-06-25T15:57:03.047

1

C++11: 15 tokens

Using only arithmetic and bitwise operators (since equality and boolean logic operators make it too easy)...

#include <iostream>

auto max(int32_t a, int32_t b, int32_t c)->int32_t {
  return c - ((c - (a - ((a - b) & (a - b) >> 31))) & (c - (a - ((a - b) & (a - b) >> 31))) >> 31);
}

auto main()->int {
  // test harness
  std::cout << max(9, 38, 7) << std::endl;
  return EXIT_SUCCESS;
}

Riot

Posted 2014-06-25T00:03:09.363

Reputation: 4 639

Fail for big numbers (>2^30), see comment http://codegolf.stackexchange.com/questions/32476/#comment68870_32477

– edc65 – 2014-06-25T21:08:27.223

Looks fine to me: http://ideone.com/pEsvG3

– Riot – 2014-06-26T08:06:51.107

Did you atctually read the comment? I think 2billions is greater than 0 [http://ideone.com/vlcnq9 ] – edc65 – 2014-06-26T08:19:50.840

Ah i see; yes it does have a problem with those numbers in your other comment, when a 0 is involved. But not for 2^30 as you said. http://ideone.com/LicmXa

– Riot – 2014-06-26T22:00:17.967

It's not the 0 involved. The problem are big numbers and overflow, try max(2000000000, -200000000, 1111111111). – edc65 – 2014-06-26T22:07:41.023

0

TIS-100, 8 operations

MOV ACC UP #A
SUB UP     #B
SUB 999
ADD 999
ADD UP     #B
SUB UP     #C
SUB 999
ADD 999
ADD UP     #C
MOV ACC DOWN

The provider(UP) only do MOVs so not shown in the code Maybe not work when too near the 999 edge

l4m2

Posted 2014-06-25T00:03:09.363

Reputation: 5 985

0

J (Not competing)

I was just wondering what the a solution in J would look like. This uses a , and a # though, so it won't be competing.

((a<b),(b<c),(c<a))#b,c,a

This would compete, but is way too long, with 9 tokens:

(b*a<:b)+(c*b<c)+(a*c<a)

ɐɔıʇǝɥʇuʎs

Posted 2014-06-25T00:03:09.363

Reputation: 4 449

0

we have the following assumptions:

  • max(a;b)=(a+b + |a-b|)/2

  • max(a;b;c)=max(max(a;b);c)

  • abs(a)=(a + (a >> 31)) ^ (a >> 31)

we can use the pseudo-code:

function max(a,b,c)

{

out1=( (a+b) + (( (a-b) + ((a-b) >> 31)) ^ ((a-b)>> 31))) div 2

out2=( (out1+c) + (( (out1-c) + ((out1-c) >> 31)) ^ ((out1-c)>> 31))) div 2

return out2

}

jihed gasmi

Posted 2014-06-25T00:03:09.363

Reputation: 101

Please write actual code, and provide the count of tokens in your answer. – ProgramFOX – 2014-06-25T18:20:38.193

0

C# (2nd try)

I got it... No integrated functions...

But is it allowed to use other integrated datatypes or just plain int? If allowed I would propose:

int foo2(int a, int b, int c)
{
   var x = new SortedList<int,int>();

   x[a] = 1;
   x[b] = 1;
   x[c] = 1;

   return x.Keys[2];
}

EvilFonti

Posted 2014-06-25T00:03:09.363

Reputation: 301

0

javascript 8 tokens

although similar to @openorclose's answer, i do actually use the logical operators for the assignment itself.

function max( a, b, c ) {
    x=( a > b && a) || b;
    return ( x > c && x ) || c;
}

fiddle

Math chiller

Posted 2014-06-25T00:03:09.363

Reputation: 337

0

R (10 tokens)

function max(a, b, c) {
  max <- a
  max <- max + (b - max) * (b > max)
  max <- max + (c - max) * (c > max)
  return(max)
}

djhurio

Posted 2014-06-25T00:03:09.363

Reputation: 1 113

0

Brainfuck (Not competing)

>,[-<+>>>+<<]>,[-<+>>>+<<]>[>[-<->>]<<]<[-]>[-]>[-]<<<[->>>>+<<<<]>>>>[-<+>>>+<<]>,[-<+>>>+<<]>[>[-<->>]<<]<<

rpax

Posted 2014-06-25T00:03:09.363

Reputation: 171

-1

VBA (6 tokens)

 Function max3(a As Integer, b As Integer, c As Integer)
 i = IIf(a >= b And a >= c, a, IIf(b >= c, b, c))
 max3 = i
 End Function  

not sure if this is not branching.

Alex

Posted 2014-06-25T00:03:09.363

Reputation: 369

It is branching, only inline. Specifically, the ubiquitous ternary operator (which this essentially is) is not one of the allowed operations. – tomsmeding – 2014-06-25T18:04:21.167

Thanks @tomsmeding, may I ask what is the ubiquitous ternary operator (is it IIF() in my code?) – Alex – 2014-06-25T18:55:02.500

yes sorry, with ubiquitous I meant that it's present in pretty much every language, and the ternary operator is your IIf, Inline-If. In most languages, it is, for example, a>=b ? a : b. It is branching indeed. – tomsmeding – 2014-06-25T18:57:52.240

-1

JavaScript: 4 tokens (** based on broad interpretation of "assignment"!)

Obviously my score of 4 is extremely generous/lenient!

To arrive at that score I've assumed "assignment" (worth 0 tokens in the question) includes such things as additive assignment, subtractive assignment, multiplicative assignment, and XOR-ing (^=) assignment

function f(a, b, c) {
  d = a;
  d -= b;
  d = d >= 0;

  a *= d;  //a = a if (a>=b), else 0
  d ^= true; //invert d
  b *= d;  //b = b if (b<a), else 0

  a += b;  //a is now max(a,b)

  d = a;
  d -= c;
  d = d >= 0;

  a *= d;  //a = a if (a>=c), else 0
  d ^= true; //invert d
  c *= d;  //c = c if (c<a), else 0
  a += c;  //a is now max(max(a,b),c)

  return a;
}

If those assignments actually count the score is 14 :)

jcdude

Posted 2014-06-25T00:03:09.363

Reputation: 99

Because d -= b is actually the same as d = d - b, I would say that you use arithmetic and that you should count this as a token. – ProgramFOX – 2014-06-26T14:27:24.253

Yes, I realise that - I was (jokingly) trying to take advantage of the meaning of "assignment". I think I made that fairly obvious! – jcdude – 2014-06-26T16:00:57.043