Questions about an XOR article - xor

https://florian.github.io/xor-trick/
There's a part in the article that reads (the first step operates on (x,y))
x ^= y # => (x ^ y, y)
y ^= x # => (x ^ y, y ^ x ^ y) = (x ^ y, x)
x ^= y # => (x ^ y ^ x, x) = (y, x)
I would have thought second line would be
y ^= x # =>(x ^ y ^ x, y ^ x) = (y, y ^ x)
then third line
x ^= y # => (y, y ^ x ^ y) = (y, x)
If that part of the article is correct and I'm in error about how it should work, any tips about what I'm missing?
Later,the article has
If we analyze the individual bits in u ^ v, then every 0 means that
the bit had the same value in both u and v. Every 1 means that the
bits differed.
Using this, we find the first 1 in u ^ v, i.e. the first position i
where u and v have to differ. Then we partition A as well as the
numbers from 1 to n according to that bit. We end up with two
partitions, each of which contains two sets:
Partition 0
The set of all values from 1 to n where the i-th bit is 0
The set of all values from A where the i-th bit is 0
Partition 1
The set of all values from 1 to n where the i-th bit is 1
The set of all values from A where the i-th bit is 1
Since u and v differ in position i, we know that they have to be in
different partitions.
Let me see if I get this. Partition 0 contains one of u or v, we don't know which. Partition 1 contains v or u, whichever wasn't in Partition 0. We operate each with ^u^v to get u and v respectively. So yes, the array has to be partitioned into two parts, and I think I understand the basis for the partition and why it has to be done (to later isolate u and v after operating ^u^v).
But why is it noted that each partition contains two sets? I'm assuming the ith bit is the first "1" bit in u^v. It wouldn't be enough to partition the array into two parts, one partition with ith bit being 0 and one partition with ith bit being 1? 🤔 What's the significance of the set of all values from 1 to n where th i-th bit is 0, or 1, respectively?
Or is it not significant that the partitions each have two sets, and the sets are just a leftover byproduct of how the partitions were determined?
Thanks for any answers.

You ask two related questions, I'll answer both:
First, in this XOR-int-swap code the commented x and y do not stand for the current variable values, rather they stand for the original values of those variables
x ^= y # => (x ^ y, y)
y ^= x # => (x ^ y, y ^ x ^ y) = (x ^ y, x)
x ^= y # => (x ^ y ^ x, x) = (y, x)
The first operation x ^= y sets x to original_x ^ original_y.
The second operation y ^= x sets y to original_y ^ original_x ^ original_y, which is just original_x.
The third operation x ^= y sets x to original_x ^ original_y ^ original_x, which becomes original_y.
The second part is about the question How can we use XOR to find two missing values in a range/sequence of numbers?.
Your understanding is correct that by using XOR on both the sequence (without missing numbers) and the array (with two missing numbers), our final result is just the XOR of the two missing numbers, since doing XOR with the same number twice cancels itself out.
Since the two missing numbers have to be different numbers, they will differ at some index i, at which their XOR will be 1.
Once we have this index we can just run the algorithm that checks for a single missing number, simply by partitioning the numbers on whether they have the i-th bit set or not. And because the two numbers differ on the i-th bit, each partition will have exactly one of the missing numbers.
why is it noted that each partition contains two sets
The word 'set' might be the confusing part here, what is meant is "a set of numbers that was XORed with", the general idea is that:
we create a variable a = 0
we XOR a with all numbers in the sequence that have the i-th bit set (this is the first 'set')
we XOR a with all numbers in our array that have the i-th bit set (this is the second 'set')
Again the XOR operations cancel each other out, just for the one missing number we executed the XOR only once, so a is 0 ^ missing_number, which is missing_number.
Find a detailed explanation of this method in this answer here.

Related

bitwise operator XOR [duplicate]

This question already has answers here:
How does XOR work in C to find a number occurring odd number of times?
(4 answers)
Closed 6 years ago.
Trying to understand the XOR importance, I found this code:
Given a set of numbers where all elements occur even number of times except one number, find the odd occurring number
But I can't visualize it.
How does the XOR bitwise operator roll out the odd element?
// Function to return the only odd occurring element
int findOdd(int arr[], int n) {
int res = 0, i;
for (i = 0; i < n; i++)
res ^= arr[i];
return res;
}
int main(void) {
int arr[] = { 12, 12, 14, 90, 14, 14, 14 };
int n = sizeof(arr) / sizeof(arr[0]);
printf("The odd occurring element is %d\n", findOdd(arr, n));
return 0;
}
Output: The odd occurring element is 90
The way I read it you are really asking two questions:
What is the importance of XOR?
How does XOR help find the odd occurrence of a number in a series?
In order to understand question (2), one must understand question (1). Understanding question (1) requires an adequate introduction to the XOR logic and the properties it has.
What is the importance of XOR?
Definition: The output of an XOR operation is TRUE if and only if the number of TRUE inputs are odd. Commonly referred to as "one or the other, but not both"
This is captured by the following truth table:
XOR Truth Table
Using the truth table it is trivial to derive the following properties:
A ^ 0 = A (The output follows the variable input)
A ^ 1 = A' (The output is the negation of the variable input)
A ^ A = 0 (The output is always zero since both inputs are equal)
(A ^ B) ^ C = A ^ (B ^ C) (Associative Property)
A ^ B = B ^ A (Communative Property)
Now on to the importance of XOR, i.e., how these properties allow folks to make useful things. The first computing layer to note is the hardware layer. XOR gates are physical devices that have utility in many fundamental logic circuits, that fundamental utility being "odd occurrence detection". Some notable applications:
Half-Adders: The truth table for a half-adders SUM output is identical to the XOR gate. (Throw an AND gate in for the carry bit). Same thing for the Full-Adder, using XOR gates for the fundamental summation with some additional supporting gates.
Inverters: Using one input as a control and the other as the "input", the xor gate can be used to invert the input signal. The control bit can be used to pass the input through as well, acting as a buffer. In software, you use these circuits to toggle bits/bytes from one state to the other. Val = Val ^ 1 (Recall the second property above).
Comparators: The output of an XOR gate is 1 when the inputs are different, 0 when they are the same. This is the driving logic for the half-adder.
In addition to these circuits we can, at a hardware level, use XOR to check byte parity for Error Detection and Correction (EDAC) operations, swap register values (without a temp variable!), and recover corrupted/lost data from hard drives in a RAID system.
However, software junkies don't care about these circuits, they want to live in the land of abstractions that provide an easy way to use this hardware in a human intuitive way. Let there be code.
How does XOR help find the odd occurrence of a number in a series?
Even though the first comment to your question indicates the poster didn't understand your question, they inadvertently answered the question correctly, but I will explain further.
Let's break down what your findOdd() function is actually doing. The for loop is literally performing the following calculation:
Result = 0 ^ 12 ^ 12 ^ 14 ^ 90 ^ 14 ^ 14 ^ 14
Recall that XOR is communative, so after a little re-ordering the calculation becomes:
Result = 0 ^ 12 ^ 12 ^ 14 ^ 14 ^ 14 ^ 14 ^ 90
Using the property A ^ A = 0 and associativity, the XOR of 12 and 12 drops to 0 as does the XOR of the 14's, leaving:
Result = 0 ^ 0 ^ 0 ^ 0 ^ 90 = 0 ^ 90 = 90
In effect, the XOR forces even occurrences to become zero and A ^ 0 = A. Hope this verbose description of XOR was helpful in visualizing what is happening under the hood.
Binary XOR is the exclusive or operation, performed one bit at a time. It is equivalent to subtraction, modulo 2.
Here is the truth table for XOR:
a b a^b
1 0 1
1 1 0
0 0 0
0 1 1
As you can see, XOR sets a bit to 1 (true) when EITHER of the input bits is 1, but not both.
Now, consider this: what is 1 xor 1? From the truth table, you know it's zero.
And what is 1 xor 1 xor 1? Well, you know 1^1==0, so that leaves 0^1, which is 1.
So you have that xor'ing a 1 bit an even number of times will produce a zero, and an odd number of times will produce a 1.
Thus, if we take a ^ a ^ a, for some value of a, we get a result where all the 1 bits in the binary representation of a are set. (Which is to say, we get back 'a'.)
Whereas if we take a ^ a ^ a ^ a, for some value of a, we get a result where all the 1 bits in the binary representation of a are 0. (Which is to say, we get back 0.)
The one exception to this, of course, is 0. The binary representation for 0 has no set bits in it, so this approach will not indicate if the number of 0's was even or odd.
But I can't visualize it
Then you should step through the code one line at a time and keep an eye on res at each iteration through the loop.
Or just do it on paper -- write down the binary form of 12, i.e. 00001100, and then XOR that value with the next value, also 00001100, which gets you back to 00000000. Then XOR the next value with that, and so on. You might want to start with a short list of pairs of numbers, like {12, 12, 15, 15} and see what happens. Then try removing the last one, so you have {12, 12, 15} and see what you get. Then try reordering the list: {12, 15, 12}. Count the number of times that each bit gets flipped.
XOR means exclusive or, for each bit in the operands, the resulting bit is 1 if either corresponding bit of the operand is 1 but not both:
0 ^ 0 = 0, 1 ^ 0 = 1, 1 ^ 0 = 0 and 1 ^ 1 = 0.
Identical numbers cancel each other as x ^ x == 0 for all values. The final outcome of xoring all elements of the array is the number occurring an odd number of times, assuming there is only one.
This method works if all duplicate numbers but one occur an even number of times and if there is a single entry occurring an odd number of times.
XOR is commutative: a ^ b equals b ^ a.
XOR is associative: a ^ (b ^ c) equals (a ^ b) ^ c.
Together these two mean that you can arbitrarily reorder operands in a chain of XORs.
Furthermore:
0 is a neutral element: a ^ 0 equals a.
Every number is its own inverse: a ^ a equals 0.
In your code we're doing 12 ^ 12 ^ 14 ^ 90 ^ 14 ^ 14 ^ 14.
We can reorder this to (12 ^ 12) ^ (14 ^ 14) ^ (14 ^ 14) ^ 90, pairing up every element that occurs an even number of times with itself.
This simplifies to 0 ^ 0 ^ 0 ^ 90 (because all pairs of equal elements cancel each other out, giving 0), which reduces to just 90 (because XORing with 0 does nothing).
This is all about XOR operator.
^ is bit-wise XOR.
For example,
12^5 == 1100^0101 == (1^0)(1^1)(0^1)(0^1) == 1011
From the mathematical definition of XOR, the output is 1 iif the number of 1(s) in inputs is odd.
This case:
When a number occurs even number of times, the binary representation will also get two 1s or two 0s in each position, making the result going to 0.
Eg:
2^2^3 == (1^1^1)(0^0^1) == 11 == 3
i.e. 10 (2)
10 (2)
11 (3)
--------
11 (3)
========
5^7^5 == (1^1^1)(0^1^0)(1^1^1) == 111
101 (5)
111 (7)
101 (5)
---------
111 (7)
=========
Note that even occurring numbers have no affect here.
Given the following axioms:
x ^ x == 0
y ^ y ^ y == y
z ^ 0 == z
Then for example:
x ^ x ^ y ^ y ^ y == y
\___/ \_______/
0 ^ y == y
Also:
x ^ y == y ^ x
So the order of the operands does not matter.
The point is an odd number of occurrences of a value results in the value, while even results in zero, and a value xor'ed with zero is the value.
Consequently as the comment at the start of the code suggests, it works only when there is a single value with an odd number of occurrences and all other values occur an even number of times. Otherwise the result is simply the xor of all the odd occurring values, e.g.:
x ^ x ^ x ^ y == x ^ y
which is neither x nor y.

A pseudo-random number generator based on 2 inputs [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
I need to generate a pseudo-random number based on 2 input values X and Y. Given the same X and Y values I need to get the same result. The result should be between 0 and 1 inclusive.
So far I have this:
const int a = 0x7fffffff / 48271;
const int b = 0x7fffffff % 48397;
float rand(int x, int y) {
float seed, result;
seed = x ^ ((y << 1) & 0x2AAAAAAA) ^ ((y >> 1) & 0x33333333);
result = 48353 * (seed % a) - b * (seed / a);
return (result);
}
It's giving me a result but not what I'm looking for. I've cobbled it together from random things I've seen on the net, so no idea if it's really any good.
Borrowing from xxHash:
float rand(uint32_t x, uint32_t y) {
/* mix around the bits in x: */
x = x * 3266489917 + 374761393;
x = (x << 17) | (x >> 15);
/* mix around the bits in y and mix those into x: */
x += y * 3266489917;
/* Give x a good stir: */
x *= 668265263;
x ^= x >> 15;
x *= 2246822519;
x ^= x >> 13;
x *= 3266489917;
x ^= x >> 16;
/* trim the result and scale it to a float in [0,1): */
return (x & 0x00ffffff) * (1.0f / 0x1000000);
}
The general idea is to subject x and y to a variety of 1:1 transforms and to mix those together to distribute all of the input bits evenly(ish) throughout the result. Then the result in floating-point to [0,1). I've excluded 1.0 from the possible outputs because including it turns out to be kind of fiddly.
Multiplication by any odd number, with unsigned overflow, is a 1:1 transform because odd numbers are all co-prime with powers of two (the range limit of a uint32_t). Unfortunately multiplication only allows low order bits to affect high order bits; it doesn't allow high bits to affect low. To make up for that, we have a few x ^= x >> k terms, to mix high bits into low positions.
To "get the same result" the PRNG state needs to be at least as many bits as the sum of x,y bit-width. float is not wide enough.
By "same result", I assume that means the same sequence of numbers generated.
long double might work for you, but it appears you need a new PRNG algorithm with a much wider state.

Bitwise C programming

Hey I have been having trouble with a C program. The program I have to write simulates the operation of a VAX computer. I have to take in 2 variables x and y to generate z.
within that there are two functions, the first
Sets Z to 1 where each bit position of y = 1
2nd sets z to 0 where each bit position of y = 1
I'm not asking for someone to do this for me, I just need an explanation on how this is carried out as I have a bare bones of the two functions that I need. I was thinking of something like this but I don't know if it's right at all.
#include<stdio.h>
int main()
{
int x1 = 1010;
int y1 = 0101;
bis(x1, y1);
bic(x1, y1);
}
/* BIT SET function that sets the result to 1 wherever y = 1 */
int bis (int x, int y)
{
int z = x & y;
int result = ?;
printf("BIT SET: \n\n", result);
return result;
}
/* BIT CLEAR function that sets result to 0 wherever y = 1 */
int bic(int x, int y)
{
int z = x & y;
int result = ?;
printf("BIT CLEAR:\n\n ", result);
return result;
}
Apologies for the poor naming conventions. Am I anyway on the right track for this program?
Let's look at bitset() first. I won't post C code, but we can solve this on paper as a start.
Say you have your integers with the following bit patterns: x = 1011 and y = 0101. (I'm changing your example numbers. And, incidentally, this is not how you would define two integers having these bit patterns, but right now we're focusing on the logic.)
If I am understanding correctly, when you call bitset(x, y), you want the answer, Z, to be 1111.
x = 1011
y = 0101
^ ^-------- Because these two bits have the value 1, then your answer also
has to set them to 1 while leaving the other bits in x alone.
Well, which bitwise operation will accomplish this? You have AND (&), OR (\), XOR (^), and COMPLEMENT (~).
In this case, you are ORing the two values. Looking at the following truth table:
x 1 0 1 1
y 0 1 0 1
-----------------
(x OR y) 1 1 1 1
Each bit in the last row is given by ORing that column in x and y. So (1 OR 0) = 1, (0 OR 1) = 1, (1 OR 0) = 1, (1 OR 1) = 1
So now you can write a C function bitset(x, y), ORs x and y, and returns the result as Z.
What bitwise operator - and you can do it in multiple steps with multiple operators - would you use to clear the bits?
x 1 0 1 1
y 0 1 0 1
-------------------------------------------
(SOME OPERATONS INVOLVING x and y) 1 0 1 0
What would those logical operators (from the list above) be? Think about the "and" and "complement" operators.
Good luck on your hw!
Bonus: A quick primer on expressing integers in C.
int x = 1337 creates an integer and gives it the value 1337. If you said x = 01337, x WILL NOT have the value "1337" like you might expect. By placing the 0 in front of the number, you're telling C that that number is in octal (base 8). The digits "1337", interpreted in base 8, is equivalent to decimal (base 10) 735. If you said x = 0x1337 then you are expressing the number in base 16, as a hexadecimal, equivalent to 4919 in base 10.
Nope... what you have there will and together two integers. One of which is 1010 (base10), and the other of which is 101 (base 8 - octal -> 65 base 10).
First you'll want to declare your constants as binary (by prefixing them with 0b).
Second, you'll want to out put them (for your instructor or TA) as a binary representation. Check out this question for more ideas

How does using XOR to find a single element with odd number of occurrences in an array work?

Consider this problem:
You are given an array containing positive integers. All the integers occur even number of times except one. Find this special integer.
Solution:
The integer with the odd number of occurrences will have 0 or more pairs and one single number. So, if we could some how get rid of all the pairs then all we'd be left with is the single number. Now, what gets rid of pairs? Hint: think of an operator.
XOR will do the trick. Its gives you O(n) solution with no extra memory.
int GetSpecialOne(int[] array, int length)
{
int specialOne = array[0];
for (int i=1; i < length; i++)
{
specialOne ^= array[i];
}
return specialOne;
}
I don't understand how reducing the array by accumulating the XOR on each element produces the special integer. How does it work?
It works because (N xor Q) xor Q = N.
Exactly one integer is present an odd number of times, so it will be the only number not to "disappear" from the list. All other numbers are present an even number of times so they all appear in groups of 2's (conceivably), so they all "disappear". Also, the "distance" between the XORs don't matter: (((N xor Z) xor Q) xor Z) xor Q = N. The Z's and the Q's "cancel out" even though there are intermediate XORs between the pairs.
The XOR operator has the property that (a ^ a) == 0, and (by extension) that (a ^ b ^ a) == b. Therefore, any value that occurs an even number of times will "cancel" out to zero in the XOR "accumulation", leaving just the odd one out.
Fact one: x XOR x is zero.
This follows from the fact that 0 XOR 0 is zero and 1 XOR 1 is zero.
Fact two: x XOR x XOR x ... x is zero where x appears an even number of times.
This follows from fact one by induction.
Fact three: x XOR x XOR x ... x is x where x appears an odd number if times.
This follows from fact two by writing the expression as
(x XOR x XOR x ... x) XOR x = 0 XOR x = x
where there are 2n terms in the parentheses if there were 2n + 1 terms in the original.
Fact four: XOR is associative and commutative.
This is trivial to verify.
Now it is clear how this code works. The numbers that appear an even number of times are reduced to zero by this code. The sole number that appears an odd number of times is reduced to itself by this code.
^ is an exclusive or operator. Both operands to the bitwise exclusive OR operator must be of integral types. The bitwise exclusive OR operator compares each bit of its first operand to the corresponding bit of its second operand. If one bit is 0 and the other bit is 1, the corresponding result bit is set to 1. Otherwise, the corresponding result bit is set to 0.
If both are either high or low, output is 0 and in all other cases output is 1.
Ex: a^b^a^a^b^c^c => ( c^c =0; b^b = 0; a^a = 0; Finally left with 0^0^0^a = a ) . So, the number which is odd times repeated among the even times repetition in the sequence is the output. You can work with the same example, taking the array elements.

Explain this snippet which finds the maximum of two integers without using if-else or any other comparison operator?

Find the maximum of two numbers. You should not use if-else or any other comparison operator. I found this question on online bulletin board, so i thought i should ask in StackOverflow
EXAMPLE
Input: 5, 10
Output: 10
I found this solution, can someone help me understand these lines of code
int getMax(int a, int b) {
int c = a - b;
int k = (c >> 31) & 0x1;
int max = a - k * c;
return max;
}
int getMax(int a, int b) {
int c = a - b;
int k = (c >> 31) & 0x1;
int max = a - k * c;
return max;
}
Let's dissect this. This first line appears to be straightforward - it stores the difference of a and b. This value is negative if a < b and is nonnegative otherwise. But there's actually a bug here - if the difference of the numbers a and b is so big that it can't fit into an integer, this will lead to undefined behavior - oops! So let's assume that doesn't happen here.
In the next line, which is
int k = (c >> 31) & 0x1;
the idea is to check if the value of c is negative. In virtually all modern computers, numbers are stored in a format called two's complement in which the highest bit of the number is 0 if the number is positive and 1 if the number is negative. Moreover, most ints are 32 bits. (c >> 31) shifts the number down 31 bits, leaving the highest bit of the number in the spot for the lowest bit. The next step of taking this number and ANDing it with 1 (whose binary representation is 0 everywhere except the last bit) erases all the higher bits and just gives you the lowest bit. Since the lowest bit of c >> 31 is the highest bit of c, this reads the highest bit of c as either 0 or 1. Since the highest bit is 1 iff c is 1, this is a way of checking whether c is negative (1) or positive (0). Combining this reasoning with the above, k is 1 if a < b and is 0 otherwise.
The final step is to do this:
int max = a - k * c;
If a < b, then k == 1 and k * c = c = a - b, and so
a - k * c = a - (a - b) = a - a + b = b
Which is the correct max, since a < b. Otherwise, if a >= b, then k == 0 and
a - k * c = a - 0 = a
Which is also the correct max.
Here we go: (a + b) / 2 + |a - b| / 2
Use bitwise hacks
r = x ^ ((x ^ y) & -(x < y)); // max(x, y)
If you know that INT_MIN <= x - y <= INT_MAX, then you can use the following, which is faster because (x - y) only needs to be evaluated once.
r = x - ((x - y) & ((x - y) >> (sizeof(int) * CHAR_BIT - 1))); // max(x, y)
Source : Bit Twiddling Hacks by Sean Eron Anderson
(sqrt( a*a + b*b - 2*a*b ) + a + b) / 2
This is based on the same technique as mike.dld's solution, but it is less "obvious" here what I am doing. An "abs" operation looks like you are comparing the sign of something but I here am taking advantage of the fact that sqrt() will always return you the positive square root so I am squaring (a-b) writing it out in full then square-rooting it again, adding a+b and dividing by 2.
You will see it always works: eg the user's example of 10 and 5 you get sqrt(100 + 25 - 100) = 5 then add 10 and 5 gives you 20 and divide by 2 gives you 10.
If we use 9 and 11 as our numbers we would get (sqrt(121 + 81 - 198) + 11 + 9)/2 = (sqrt(4) + 20) / 2 = 22/2 = 11
The simplest answer is below.
#include <math.h>
int Max(int x, int y)
{
return (float)(x + y) / 2.0 + abs((float)(x - y) / 2);
}
int Min(int x, int y)
{
return (float)(x + y) / 2.0 - abs((float)(x - y) / 2);
}
int max(int i, int j) {
int m = ((i-j) >> 31);
return (m & j) + ((~m) & i);
}
This solution avoids multiplication.
m will either be 0x00000000 or 0xffffffff
Using the shifting idea to extract the sign as posted by others, here's another way:
max (a, b) = new[] { a, b } [((a - b) >> 31) & 1]
This pushes the two numbers into an array with the maximum number given by the array-element whose index is sign bit of the difference between the two numbers.
Do note that:
The difference (a - b) may overflow.
If the numbers are unsigned and the >> operator refers to a logical right-shift, the & 1 is unnecessary.
Here's how I think I'd do the job. It's not as readable as you might like, but when you start with "how do I do X without using the obvious way of doing X, you have to kind of expect that.
In theory, this gives up some portability too, but you'd have to find a pretty unusual system to see a problem.
#define BITS (CHAR_BIT * sizeof(int) - 1)
int findmax(int a, int b) {
int rets[] = {a, b};
return rets[unsigned(a-b)>>BITS];
}
This does have some advantages over the one shown in the question. First of all, it calculates the correct size of shift, instead of being hard-coded for 32-bit ints. Second, with most compilers we can expect all the multiplication to happen at compile time, so all that's left at run time is trivial bit manipulation (subtract and shift) followed by a load and return. In short, this is almost certain to be pretty fast, even on the smallest microcontroller, where the original used multiplication that had to happen at run-time, so while it's probably pretty fast on a desktop machine, it'll often be quite a bit slower on a small microcontroller.
Here's what those lines are doing:
c is a-b. if c is negative, a<b.
k is 32nd bit of c which is the sign bit of c (assuming 32 bit integers. If done on a platform with 64 bit integers, this code will not work). It's shifted 31 bits to the right to remove the rightmost 31 bits leaving the sign bit in the right most place and then anding it with 1 to remove all the bits to the left (which will be filled with 1s if c is negative). So k will be 1 if c is negative and 0 if c is positive.
Then max = a - k * c. If c is 0, this means a>=b, so max is a - 0 * c = a. If c is 1, this means that a<b and then a - 1 * c = a - (a - b) = a - a + b = b.
In the overall, it's just using the sign bit of the difference to avoid using greater than or less than operations. It's honestly a little silly to say that this code doesn't use a comparison. c is the result of comparing a and b. The code just doesn't use a comparison operator. You could do a similar thing in many assembly codes by just subtracting the numbers and then jumping based on the values set in the status register.
I should also add that all of these solutions are assuming that the two numbers are integers. If they are floats, doubles, or something more complicated (BigInts, Rational numbers, etc.) then you really have to use a comparison operator. Bit-tricks will not generally do for those.
getMax() Function Without Any Logical Operation-
int getMax(int a, int b){
return (a+b+((a-b)>>sizeof(int)*8-1|1)*(a-b))/2;
}
Explanation:
Lets smash the 'max' into pieces,
max
= ( max + max ) / 2
= ( max + (min+differenceOfMaxMin) ) / 2
= ( max + min + differenceOfMaxMin ) / 2
= ( max + min + | max - min | ) ) / 2
So the function should look like this-
getMax(a, b)
= ( a + b + absolute(a - b) ) / 2
Now,
absolute(x)
= x [if 'x' is positive] or -x [if 'x' is negative]
= x * ( 1 [if 'x' is positive] or -1 [if 'x' is negative] )
In integer positive number the first bit (sign bit) is- 0; in negative it is- 1. By shifting bits to the right (>>) the first bit can be captured.
During right shift the empty space is filled by the sign bit. So 01110001 >> 2 = 00011100, while 10110001 >> 2 = 11101100.
As a result, for 8 bit number shifting 7 bit will either produce- 1 1 1 1 1 1 1 [0 or 1] for negative, or 0 0 0 0 0 0 0 [0 or 1] for positive.
Now, if OR operation is performed with 00000001 (= 1), negative number yields- 11111111 (= -1), and positive- 00000001 (= 1).
So,
absolute(x)
= x * ( 1 [if 'x' is positive] or -1 [if 'x' is negative] )
= x * ( ( x >> (numberOfBitsInInteger-1) ) | 1 )
= x * ( ( x >> ((numberOfBytesInInteger*bitsInOneByte) - 1) ) | 1 )
= x * ( ( x >> ((sizeOf(int)*8) - 1) ) | 1 )
Finally,
getMax(a, b)
= ( a + b + absolute(a - b) ) / 2
= ( a + b + ((a-b) * ( ( (a-b) >> ((sizeOf(int)*8) - 1) ) | 1 )) ) / 2
Another way-
int getMax(int a, int b){
int i[] = {a, b};
return i[( (i[0]-i[1]) >> (sizeof(int)*8 - 1) ) & 1 ];
}
static int mymax(int a, int b)
{
int[] arr;
arr = new int[3];
arr[0] = b;
arr[1] = a;
arr[2] = a;
return arr[Math.Sign(a - b) + 1];
}
If b > a then (a-b) will be negative, sign will return -1, by adding 1 we get index 0 which is b, if b=a then a-b will be 0, +1 will give 1 index so it does not matter if we are returning a or b, when a > b then a-b will be positive and sign will return 1, adding 1 we get index 2 where a is stored.
#include<stdio.h>
main()
{
int num1,num2,diff;
printf("Enter number 1 : ");
scanf("%d",&num1);
printf("Enter number 2 : ");
scanf("%d",&num2);
diff=num1-num2;
num1=abs(diff);
num2=num1+diff;
if(num1==num2)
printf("Both number are equal\n");
else if(num2==0)
printf("Num2 > Num1\n");
else
printf("Num1 > Num2\n");
}
The code which I am providing is for finding maximum between two numbers, the numbers can be of any data type(integer, floating). If the input numbers are equal then the function returns the number.
double findmax(double a, double b)
{
//find the difference of the two numbers
double diff=a-b;
double temp_diff=diff;
int int_diff=temp_diff;
/*
For the floating point numbers the difference contains decimal
values (for example 0.0009, 2.63 etc.) if the left side of '.' contains 0 then we need
to get a non-zero number on the left side of '.'
*/
while ( (!(int_diff|0)) && ((temp_diff-int_diff)||(0.0)) )
{
temp_diff = temp_diff * 10;
int_diff = temp_diff;
}
/*
shift the sign bit of variable 'int_diff' to the LSB position and find if it is
1(difference is -ve) or 0(difference is +ve) , then multiply it with the difference of
the two numbers (variable 'diff') then subtract it with the variable a.
*/
return a- (diff * ( int_diff >> (sizeof(int) * 8 - 1 ) & 1 ));
}
Description
The first thing the function takes the arguments as double and has return type as double. The reason for this is that to create a single function which can find maximum for all types. When integer type numbers are provided or one is an integer and other is the floating point then also due to implicit conversion the function can be used to find the max for integers also.
The basic logic is simple, let's say we have two numbers a & b if a-b>0(i.e. the difference is positive) then a is maximum else if a-b==0 then both are equal and if a-b<0(i.e. diff is -ve) b is maximum.
The sign bit is saved as the Most Significant Bit(MSB) in the memory. If MSB is 1 and vice-versa. To check if MSB is 1 or 0 we shift the MSB to the LSB position and Bitwise & with 1, if the result is 1 then the number is -ve else no. is +ve. This result is obtained by the statement:
int_diff >> (sizeof(int) * 8 - 1 ) & 1
Here to get the sign bit from the MSB to LSB we right shift it to k-1 bits(where k is the number of bits needed to save an integer number in the memory which depends on the type of system). Here k= sizeof(int) * 8 as sizeof() gives the number of bytes needed to save an integer to get no. of bits, we multiply it with 8. After the right shift, we apply the bitwise & with 1 to get the result.
Now after obtaining the result(let us assume it as r) as 1(for -ve diff) and 0(for +ve diff) we multiply the result with the difference of the two numbers, the logic is given as follows:
if a>b then a-b>0 i.e., is +ve so the result is 0(i.e., r=0). So a-(a-b)*r => a-(a-b)*0, which gives 'a' as the maximum.
if a < b then a-b<0 i.e., is -ve so the result is 1(i.e., r=1). So a-(a-b)*r => a-(a-b)*1 => a-a+b =>b , which gives 'b' as the maximum.
Now there are two remaining points 1. the use of while loop and 2. why I have used the variable 'int_diff' as an integer. To answer these properly we have to understand some points:
Floating type values cannot be used as an operand for the bitwise operators.
Due to above reason, we need to get the value in an integer value to get the sign of difference by using bitwise operators. These two points describe the need of variable 'int_diff' as integer type.
Now let's say we find the difference in variable 'diff' now there are 3 possibilities for the values of 'diff' irrespective of the sign of these values. (a). |diff|>=1 , (b). 0<|diff|<1 , (c). |diff|==0.
When we assign a double value to integer variable the decimal part is lost.
For case(a) the value of 'int_diff' >0 (i.e.,1,2,...). For other two cases int_diff=0.
The condition (temp_diff-int_diff)||0.0 checks if diff==0 so both numbers are equal.
If diff!=0 then we check if int_diff|0 is true i.e., case(b) is true
In the while loop, we try to get the value of int_diff as non-zero so that the value of int_diff also gets the sign of diff.
Here are a couple of bit-twiddling methods to get the max of two integral values:
Method 1
int max1(int a, int b) {
static const size_t SIGN_BIT_SHIFT = sizeof(a) * 8 - 1;
int mask = (a - b) >> SIGN_BIT_SHIFT;
return (a & ~mask) | (b & mask);
}
Explanation:
(a - b) >> SIGN_BIT_SHIFT - If a > b then a - b is positive, thus the sign bit is 0, and the mask is 0x00.00. Otherwise, a < b so a - b is negative, the sign bit is 1 and after shifting, we get a mask of 0xFF..FF
(a & ~mask) - If the mask is 0xFF..FF, then ~mask is 0x00..00 and then this value is 0. Otherwise, ~mask is 0xFF..FF and the value is a
(b & mask) - If the mask is 0xFF..FF, then this value is b. Otherwise, mask is 0x00..00 and the value is 0.
Finally:
If a >= b then a - b is positive, we get max = a | 0 = a
If a < b then a - b is negative, we get max = 0 | b = b
Method 2
int max2(int a, int b) {
static const size_t SIGN_BIT_SHIFT = sizeof(a) * 8 - 1;
int mask = (a - b) >> SIGN_BIT_SHIFT;
return a ^ ((a ^ b) & mask);
}
Explanation:
Mask explanation is the same as for Method 1. If a > b the mask is 0x00..00, otherwise the mask is 0xFF..FF
If the mask is 0x00..00, then (a ^ b) & mask is 0x00..00
If the mask is 0xFF..FF, then (a ^ b) & mask is a ^ b
Finally:
If a >= b, we get a ^ 0x00..00 = a
If a < b, we get a ^ a ^ b = b
//In C# you can use math library to perform min or max function
using System;
class NumberComparator
{
static void Main()
{
Console.Write(" write the first number to compare: ");
double first_Number = double.Parse(Console.ReadLine());
Console.Write(" write the second number to compare: ");
double second_Number = double.Parse(Console.ReadLine());
double compare_Numbers = Math.Max(first_Number, second_Number);
Console.Write("{0} is greater",compare_Numbers);
}
}
No logical operators, no libs (JS)
function (x, y) {
let z = (x - y) ** 2;
z = z ** .5;
return (x + y + z) / 2
}
The logic described in a problem can be explained as if 1st number is smaller then 0 will be subtracted else difference will be subtracted from 1st number to get 2nd number.
I found one more mathematical solution which I think is bit simpler to understand this concept.
Considering a and b as given numbers
c=|a/b|+1;
d=(c-1)/b;
smallest number= a - d*(a-b);
Again,The idea is to find k which is wither 0 or 1 and multiply it with difference of two numbers.And finally this number should be subtracted from 1st number to yield the smaller of the two numbers.
P.S. this solution will fail in case 2nd number is zero
There is one way
public static int Min(int a, int b)
{
int dif = (int)(((uint)(a - b)) >> 31);
return a * dif + b * (1 - dif);
}
and one
return (a>=b)?b:a;
int a=151;
int b=121;
int k=Math.abs(a-b);
int j= a+b;
double k1=(double)(k);
double j1= (double) (j);
double c=Math.ceil(k1/2) + Math.floor(j1/2);
int c1= (int) (c);
System.out.println(" Max value = " + c1);
Guess we can just multiply the numbers with their bitwise comparisons eg:
int max=(a>b)*a+(a<=b)*b;

Resources