'Find value unequal to any value from a given set of distinct values using macro
Question: how to implement a macro E that expands to an integer constant expression such that ...
(E != (X) && E != (Y) && E != (Z))
... evaluates to 1 for every choice of X, Y, and Z as integer constant expressions with distinct, nonnegative values?
Example:
#define X 13
#define Y 45
#define Z 76
#define E FUNC(X,Y,Z)
#define FUNC(X,Y,Z) ??
E /* evaluates to any number distinct from all of 13, 45, and 76 */
Which formula to use? Any ideas?
Solution 1:[1]
Given any 3 numbers
X,YandZ, produce anintconstant that is different from all 3 values.
It seems obvious that either 0, 1, 2 or 3 must meet the criteria. So here is a solution:
#define FUNC(x,y,z) (((x) != 0 && (y) != 0 && (z) != 0) ? 0 : \
((x) != 1 && (y) != 1 && (z) != 1) ? 1 : \
((x) != 2 && (y) != 2 && (z) != 2) ? 2 : 3)
Here is a more subtle solution evaluating to 0, 1, 2 or 3 depending on the last 2 bits of each of the arguments, but evaluating the arguments only once:
#define FUNC(x,y,z) ((int)((0x10201030102010 >> \
(4 * ((1 << ((x) & 3)) | \
(1 << ((y) & 3)) | \
(1 << ((z) & 3))))) & 3))
Explanation:
- we compose a number between 1 and 14 where each bit is set if one of the arguments has its last 2 bits with this value.
- multiply this value by
4and shift the magic number0x10201030102010by that much and mask by 3 to select a value that is different from all remainders.
A less readable version would multiply by 2 and shift 0x484C484, using just 32-bit arithmetic:
#define FUNC(x,y,z) ((int)((0x484C484 >> ((2 << ((x) & 3)) | \
(2 << ((y) & 3)) | \
(2 << ((z) & 3)))) & 3))
Solution 2:[2]
Although not as direct as @chqrlie first answer, I wanted to add the following finding:
Only 2 bits of
x, y, zare needed to generate a distinctive value.
If the least-significant-bit of all 3 x,y,z are the same, return x^1.
Otherwise ^ 2 with the different x,y,z.
#define FUNC2BITS(x,y,z) ( \
(((x)&1 == (y)&1) && ((y)&1 == (z)&1)) ? (x)^1 : \
(((x)&1 == (y)&1) ) ? (z)^2 : \
(((x)&1 == (z)&1) ) ? (y)^2 : (x)^2)
#define FUNC(x,y,z) FUNC2BITS((x)&3, (y)&3, (z)&3)
Above does not rely on x,y,z being distinct nor restrict them to non-negative. As OP has "with distinct, nonnegative values", can simplify to
#define FUNC2BITS(x,y,z) ( \
(((x)&1 == (y)&1) ) ? (z)^2 : \
(((x)&1 == (z)&1) ) ? (y)^2 : (x)^2)
Solution 3:[3]
Idea: find current max/min and (if can) add/subtract 1:
#include <limits.h>
#define FUNC(X,Y,Z) \
MAX(X,MAX(Y,Z)) < INT_MAX ? MAX(X,MAX(Y,Z))+1 : \
MIN(X,MIN(Y,Z)) > 0 ? MIN(X,MAX(Y,Z))-1 : \
-1 /* hard case: don't know yet how to implment */
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
int x1 = FUNC(23,45,78); // 79
int x2 = FUNC(0,45,78); // 79
int x3 = FUNC(23,INT_MAX,78); // 22
int x4 = FUNC(0,1,2); // 3
int x5 = FUNC(INT_MAX,34,0); // -1 (hard case)
If cannot add/subtract 1 (e.g. 0, 45, INT_MAX), then "don't know yet".
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 | pmor |
