Greater than function in C - c

I know this is an age old question and you probably have come across this aswell, but there's a bug in my solution and I don't know how to solve it. I need to write a function that compares two integers. I am only allowed to use the operations (!,~,&,^,|,+,>>,<<) and also no control structures(if,else loops etc).
isGreater(int x, int y) {
//returns 1 if x > y.
return ((y+(~x+1))>>31)&1;
}
my idea is simple, we compute y-x, we shift by 31 to get the sign bit, if it's negative, then we return zero else we return 1. This fails when x is negative and falsly returns 1 although it should return zero. I'm stuck at this and don't know how to proceed.
We assume that integer is 32bits and uses two's complement representation. This question is NOT about portability.
Some help would be much appreciated.
Thanks in advance

Hacker's Delight has a chapter Comparison Predicates, which is exactly what we need here.
One of the things it writes is:
x < y: (x - y) ^ ((x ^ y) & ((x - y) ^ x))
Which we can use almost directly, except that x and y should be swapped, the subtractions must be replaced by something legal, and the result appears in the top bit instead of the lowest bit. Fortunately a - b == ~(~a + b) so that's not too hard. First applying those transformations:
// swap x <-> y
(y - x) ^ ((y ^ x) & ((y - x) ^ y))
// rewrite subtraction
~(~y + x) ^ ((y ^ x) & (~(~y + x) ^ y))
// get answer in lsb
((~(~y + x) ^ ((y ^ x) & (~(~y + x) ^ y))) >> 31) & 1
I have a website here that says it works.
If local variables are allowed it can be simplified a bit by factoring out the subexpression
~(~y + x):
int diff = ~(~y + x);
return ((diff ^ ((y ^ x) & (diff ^ y))) >> 31) & 1;

First of all let's clarify that we assume:
negative integers are represented in 2's complement
int is exactly 32 bits wide and long long is exactly 64 bits wide
right shifting a negative number is an arithmetic shift
There is a problem with the (~x+1) part in your solution which is supposed to return -x. The problem is that the absolute value of INT_MIN is greater than the absolute value of INT_MAX, thus when x is INT_MIN then (~x+1) yields INT_MIN instead of -INT_MIN as you expected.
There's also a problem with overflows in the y+(-x) part of your solution (second step).
Now if you're allowed to use other types than int, we can solve both of these problems by casting the values to long long before the conversion, assuming that it's a 64-bit type, so that (~x+1) would return the expected result -x and y+(-x) would not cause any overflows. Then, obviously, we will have to change the >>31 bit to >>63.
The end solution is as follows:
static bool isGreater(int x, int y) {
long long llx = x;
long long lly = y;
long long result = ((lly+(~llx+1))>>63)&1;
return result;
}
It's feasible to test it with some corner-cases, such as x == INT_MIN, x == 0 and x == INT_MAX:
int main(void) {
int x = INT_MIN;
for (long long y = INT_MIN; y <= INT_MAX; ++y) {
assert(isGreater(x, y) == (x > y));
}
x = INT_MAX;
for (long long y = INT_MIN; y <= INT_MAX; ++y) {
assert(isGreater(x, y) == (x > y));
}
x = 0;
for (long long y = INT_MIN; y <= INT_MAX; ++y) {
assert(isGreater(x, y) == (x > y));
}
}
This was successful on my particular machine with my particular compiler. The testing took 163 seconds.
But again, this depends on being able to use other types than int (but then again with more work you could emulate long long with int).
This whole thing could be more portable if you used int32_t and int64_t instead of int and long long, accordingly. However, it still would not be portable:
ISO/IEC 9899:2011 ยง6.5.7 Bitwise shift operators
5 The result of E1 >> E2is E1 right-shifted E2 bit positions. If E1 has an unsigned type or if E1 has a signed type and a nonnegative value, the value of the result is the integral part of the quotient of E1 / 2E2. If E1 has a signed type and a negative value, the resulting value is implementation-defined.

Related

C checking for overflow during subtraction

I've been trying to determine whether there is overflow when subtracting two numbers of 32 bits. The rules I was given are:
Can only use: ! ~ & ^ | + << >>
* Max uses: 20
Example: subCheck(0x80000000,0x80000000) = 1,
* subCheck(0x80000000,0x70000000) = 0
No conditionals, loops, additional functions, or casting
So far I have
int dif = x - y; // dif is x - y
int sX = x >> 31; // get the sign of x
int sY = y >> 31; // get the sign of y
int sDif = dif >> 31; // get the sign of the difference
return (((!!sX) & (!!sY)) | (!sY)); // if the sign of x and the sign of y
// are the same, no overflow. If y is
// 0, no overflow.
I realize now I cannot use subtraction in the actual function (-), so my entire function is useless anyways. How can I use a different method than subtraction and determine whether there is overflow using only bitwise operations?
Thank you all for your help! Here is what I came up with to solve my issue:
int ny = 1 + ~y; // -y
int dif = x + ny; // dif is x - y
int sX = x >> 31; // get the sign of x
int sY = y >> 31; // get the sign of -y
int sDif = dif >> 31; // get the sign of the difference
return (!(sX ^ sY) | !(sDif ^ sX));
Every case I tried it with worked. I changed around what #HackerBoss suggested by getting the sign for y rather than ny and then reversing the two checks in the return statement. That way, if the signs are the same, or if the sign of the result and the sign of x are the same, it returns true.
Please buy and read Hacker's Delight for this stuff. Its a very good book.
int overflow_subtraction(int a, int b, int overflow)
{
unsigned int sum = (unsigned int)a - (unsigned int)b; // wrapround subtraction
int ssum = (int)sum;
// Hackers Delight: section Overflow Detection, subsection Signed Add/Subtract
// Let sum = a -% b == a - b - carry == wraparound subtraction.
// Overflow in a-b-carry occurs, iff a and b have opposite signs
// and the sign of a-b-carry is opposite of a (or equivalently same as b).
// Faster routine: res = (a ^ b) & (sum ^ a)
// Slower routine: res = (sum^a) & ~(sum^b)
// Oerflow occured, iff (res < 0)
if (((a ^ b) & (ssum ^ a)) < 0)
panic();
return ssum;
}
To avoid undefined behavior, I will assume that integers are represented in two's complement, inferred from your calculation of sX, sY, and sDif. I will also assume that sizeof(int) is 4. It would probably be better to use int32_t if you are working only with 32-bit integers, since the size of int can vary by platform.
Since you are allowed to use addition, you can think of subtraction as addition of the negation of a number. A number stored in two's complement may be negated by flipping all of the bits and adding one. This gives the following modified code:
int ny = 1 + ~y; // -y
int dif = x + ny; // dif is x - y
int sX = x >> 31; // get the sign of x
int sNY = ny >> 31; // get the sign of -y
int sDif = dif >> 31; // get the sign of the difference
return ((sX ^ sNY) | (~sDif ^ sX)); // if the sign of x and the sign of y
// are the same, no overflow. If the
// sign of dif is the same as the signs
// of x and -y, no overflow.

C programming type casting and fixed point

How should you implement this function in C code?
U16 newValue function(U16 value, S16 x, U16 y){
newValue = min((((value - x) * y) >> 10) >> 4, 4095)
return newValue
}
y is fixed point with 10 fractional bits
If x is greater then value the final result should be 0.
My concern is the mix between different types especially and that overflow does not occur. Also how to write it in a clean why if there will be a lot of type casts.
You need to code the fucntion for all possible values of the parameters given in input. Take the expression (value - x). If value is equal to 2^16 and x is equal to 2^(-15), then the result of (value - x) would be 98304, bigger than a U16. Therefore, I would cast value to S32 before this operation.
Let's collapse the expression (value - x) to its maximum value 98304. The maximum value of the expression ((value - x) * y) would then be 98304 * 2^16 which is equal to 6442450944, which is a bigger value than a 32 bits integer can hold. Therefore, you'd need to compute this expression as an U64. You can simply replace the initial U32 cast to a S64 cast, since you'll need it anyway.
Right bit shift operations only reduce the number of significant bits. Therefore, this does not require a bigger number of bits to be computed.
The min call ensures that the result cannot be bigger than 4095, which can be held in a U16; no more cast should be necessary.
Final function:
uint16_t newValue(uint16_t value, int16_t x, uint16_t y){
int64_t newValue = (int64_t)(value);
newValue -= x;
newValue *= y;
newValue >>= 10;
newValue >>= 4;
newValue = min(newValue, 4095);
// Or as a one liner.
// uint64_t newValue = min(((((int64_t)value - x) * y) >> 10) >> 4, 4095);
return (uint16_t) newValue;
}
Here it is
unsigned int function(unsigned int value, signed int x, unsigned int y){
if((((value - x) * y) >> 10) >> 4<4095)
return (((value - x) * y) >> 10) >> 4;
else return 4095;
}

How can i determine if I can compute x+y without overflow in C? [duplicate]

This question already has answers here:
Detecting signed overflow in C/C++
(13 answers)
Closed 7 years ago.
I can only use the operations ! ~ & ^ ! + << >>, and I'm having trouble grasping overflow, could use any tips or help!
It depends on whether the numbers are signed or unsigned.
If both operands are unsigned, overflow will wrap back around to 0.
If one or both operands are signed, the behavior is implementation defined, however most implementations represent signed integers in 2's complement, so in those cases positive overflow will wrap around to the negative side, and negative overflow will wrap around to the positive side.
In the case of unsigned overflow, the result will be less than at least one operand, so you can test for it this way:
if ((x + y < x) || (x + y < y) {
printf("overflow\n");
}
In the signed case, you first need to check whether both are positive (and check for negative wraparound) or both are negative (and check for positive wraparound):
if ((x > 0) && (y > 0) && ((x + y < x) || (x + y < y))) {
printf("negative overflow\n");
}
if ((x < 0) && (y < 0) && ((x + y > x) || (x + y > y))) {
printf("positive overflow\n");
}
As I mentioned before, the signed case is implementation defined, and the above will only work if signed integers are represented as 2's complement. In practice however, this will typically be the case.
This should give you an idea of how overflow works, although it doesn't use only the specific operators you mentioned. With this, you should be able to figure out how to use those other operators to achieve what the expressions above do.
With signed integer math, unless you have access to the limits like INT_MAX INT_MIN, there is no answer that gets around undefined behavior.
#include <limits.h>
int is_overflow_add_signed(int a, int b) {
// This uses -, so does not meet OP's goal.
// Available as a guide
return (a < 0) ? (b < INT_MIN - a) : (b > INT_MAX - a);
}
With unsigned math, simply see if the result "wrapped" around.
int is_overflow_add_unsigned(unsigned a, unsigned b) {
return (a + b) < a;
}
As pointed by many peoples, it is not right for signed...
So I changed it for unsigned first.
You need to calculate part by part.
Since you didn't tell us the data type, I assumed it is 4 byte unsigned data.
unsigned long x, unsigned long y;
// x = ...
// y = ...
unsigned long first_byte_x = (x & 0xFF000000) >> 24;
unsigned long first_byte_y = (y & 0xFF000000) >> 24;
unsigned long other_bytes_x = x & 0x00FFFFFF;
unsigned long other_bytes_y = y & 0x00FFFFFF;
unsigned long other_bytes_sum = other_bytes_x + other_bytes_y;
unsigned long carry = (other_bytes_sum & 0xFF000000) >> 24;
unsigned long first_byte_sum = first_byte_x + first_byte_y + carry;
if (first_byte_sum > 0xFF)
// overflow
else
// not overflow
If you can use mod(%), then it will be more simple.
*It looks like a homework so I hoped you considered enough before your asking...

Hex of most significant nibble

I am having trouble with bitwise manipulation.
To do: The hex value of the most significant nibble of x equals y (assume 0 <= y <= 15)
Restrictions: may not use equality (==) or inequality (!=) tests, relative comparison operators, division, modulus, and multiplication, conditionals.
Problem: I need to make my function so that when msb = y it returns 1 and if it is not true 0. However, I keep getting zero even when i run it with 0xff. If someone could point me in the right direction that would be great. Thank you.
int sig_nib(int x, int y){
int shifright = x >> 27;
int result = shifright & y;
return (result ^ y);
}
Silly restrictions. Who broke your compiler?
Something like this should do it:
bool sig_nib(int x, int y)
{
const int top4 = (x >> 28) & 0xf;
return !(top4 ^ y);
}
It uses Boolean inversion (!) to re-interpret the integer result from the bitwise-xor.

Finding the output of 2**32 % x in arc4random.c

I saw some code (in arc4random.c of libbsd) calculating 2**32 % x. A cleaned up version is below:
uint32_t x;
...
if (x >= 2) {
/* Calculate (2**32 % x) avoiding 64-bit math */
if (x > 0x80000000)
mod_res = 1 + ~x; /* 2**32 - x */
else {
/* (2**32 - (x * 2)) % x == 2**32 % x when x <= 2**31 */
mod_res = ((0xffffffff - (x * 2)) + 1) % x;
}
}
While the reasoning makes sense, my question is whether are there some obscure reasons not to use a simpler:
uint32_t x;
...
if (x >= 2) {
/* Calculate (2**32 % x) avoiding 64-bit math */
mod_res = -x % x;
}
Your code won't work on a machine where int is larger than 32 bits. In this case, in the expression -x, the operand would be promoted to int type, and thus become signed. This would cause the result of the expression -x % x to always be zero.
This behavior is due to C's integer promotion rules, which state that if an int can represent all values of an operand, then that operand will be promoted to an int. While this always preserves value, it may change the signedness of the type.
On a compiler with 32-bit ints it would work correctly, because unsigned int would not be promoted to int, and so -x would be equal to 2**32 - x.
Your version can be fixed by casting the promoted value back to unsigned:
mod_res = ((uint32_t) -x) % x;
Here is an example demonstrating this with a 16-bit type on a machine with 32-bit ints.

Resources