'c++ max & min without if or else [closed]

I want a way to cout << maximum & minimum of two numbers with cin >> without if() or else(). I tried before and I just found the if and else way. I want the way even without ?.



Solution 1:[1]

You may want to look at https://en.cppreference.com/w/cpp/algorithm/minmax.

#include <iostream>
#include <algorithm>

...
auto s = std::minmax(10, 2);
std::cout << s.first << ", " << s.second << "\n";     

Do resist the temptation to write a macro or so.

Solution 2:[2]

I think you might be interested in branchless programming (this isn't really the best link, but it'll hopefully be enough to get started if you've never heard of this - I couldn't find anything better with a quick google).

Here's a way to do it with no conditional jumps - nor using any functions that wrap the conditional jumps:

// given two numbers, x and y
int min = (x < y)*x + (y <= x)*y;
int max = (x > y)*x + (y >= x)*y;

demo

This works because the comparison operators return 0 if false, and 1 if true. This is basically the whole idea of branchless programming.

As much as this is fun, it's not very readable and may actually hinder performance in places like this - and a compiler will often do this kind of thing for you behind the scenes if it deems it worth it.

Solution 3:[3]

Simple way with abs, but make sure the values do not overflow (not int overflow safe)

int max = (abs(a-b)+a+b)/2;
int min = (-abs(a-b)+a+b)/2;

Because a+b = min+max

and

abs(a-b) = max-min

Overflowing of signed ints leads to undefined behavior; if you cast to unsigned ints before the arithmetic operations and back to signed ints for the abs instead you just get a wrong result, when the numbers overflow. Simple checking would need conditionals.

Alternative way with 64-bit operations (int overflow safe)

If int is shorter than 64-bit, then this would work:

unsigned long long int ulla = static_cast<unsigned long long int>(a);
unsigned long long int ullb = static_cast<unsigned long long int>(b);
int max = static_cast<int>((abs(ulla-ullb)+ulla+ullb)/2);
int min = static_cast<int>((-abs(ulla-ullb)+ulla+ullb)/2);

Alternative way with boolean operations (int overflow safe)

(implemented for 32-bit ints, needs C++20 for guaranteed two's complement of signed numbers)

unsigned int ua = static_cast<unsigned int>(a);
unsigned int ub = static_cast<unsigned int>(b);
unsigned int uha = static_cast<unsigned int>(a/2);
unsigned int uhb = static_cast<unsigned int>(b/2);
// (b/2 larger) or (equal and (b larger))
unsigned int maskmsb = ((uha-uhb) ¦ ((uha - uhb) ^ (uha - uhb - 1)) & (ua - ub)) >> 31;
unsigned int mask2 = maskmsb - 1;
unsigned int mask1 = ~mask2;

max = static_cast<int>((ub & mask1) ¦ (ua & mask2));
min = static_cast<int>((ub & mask2) ¦ (ua & mask1));

Boolean operations should be normally only done on unsigned types, so we cast. Casting back and forth between signed and unsigned numbers should keep the value for any signed number.

The complicated mask calculation is for generating 'the 33th bit' when comparing. Alternatively we could use 64 bit calculations, then the mask is just maskmsb = (ulla-ullb) >> 63.

unsigned long long int ulla = static_cast<unsigned long long int>(a);
unsigned long long int ullb = static_cast<unsigned long long int>(b);
unsigned int maskmsb = (ulla - ullb) >> 63;
unsigned long long int mask2 = maskmsb - 1;
unsigned long long int mask1 = ~mask2;

max = static_cast<int>((ullb & mask1) ¦ (ulla & mask2));
min = static_cast<int>((ullb & mask2) ¦ (ulla & mask1));

As all the casting between signed and unsigned integer of same bit width is just interpretation of the number, the code looks a lot longer than what it ends up as in assembly. (But it is still suboptimal, because CPUs have flag registers just for this.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3