C checking for overflow during subtraction - c

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.

Related

Make a function that returns 1 if x < y , otherwise return 0

Editor's note: This is one quiz from CS:APP Data Lab, where the intention is to teach 2's complement integer representation (so please don't comment about poor C practices). There are extra assumptions and restrictions over ISO C:
int is 32 bits, using 2's complement representation
Signed integer overflow wraps around (-fwrapv)
Right-shifting is arithmetic on signed types, i.e., the MSB is duplicated to fill in the shifted bits
As part of a coding project in my coding class, one that teaches C, we were given a number of bit manipulation questions with restrictions. Seen here:
CheckIfLess - if x < y then return 1, else return 0
* Example: CheckIfLess(4,5) = 1.
* Legal operations: ! ~ & ^ | + >>
* Max ops: 13
*/
Besides the legal operations listed, I can't use any statements such as do, if, while, or else. I can't cast to other data types either. Also I can't use any constant bigger than 0xFF, not that I think it'll come up for this problem. Also, assume we are using a 32 bit machine.
Here is my code so far:
int CheckIfLess(int x, int y) {
int xSign, ySign, same, diffSign, ovfTrue, ovfFalse;
same = !(x ^ y); //1 if same, else 0
xSign = x >> 31; //get sign of x
ySign = y >> 31; //get sign of y
diffSign = (x + ~y + 1) >> 31; //(x - y) then checking if they have a diff sign
// These are for overflow cases
ovfTrue = xSign & ~ySign;
ovfFalse = xSign | ~ySign;
return !!((ovfTrue | ~diffSign) & ovfFalse);
}
One thing that I know everyone will point out is that the 'same' variable isn't implemented in the answer. This is because I'm not sure were to put it to be honest. Also, I'm already 3 operations over the limit, so I need to cut out some stuff.
Could you explain your answers to me really well, I've only been learning C for just shy of a month. Also, can you explain how I'd go about reversing the function so that it would return 1 if x > y instead of x < y, else return 0?
Edit: I can't use -. I'm just supposed to use the legal operations listed in the first code chuck
Edit2: Updated my notes on the code based on what I think each statement does. Changed the x - y statement to actually be x - y instead of y - x.
Edit3: added bolded question at bottom
If x and y have different sign bits, then we only have to check if x is negative.
Else, we can check if x-y is negative
That would be:
return (x<0 != y<0) ? (x<0) : (x-y)<0;
Let's now rewrite those operations with the ones we have:
t < 0 ==> t >> 31
x-y ==> x + ~y + 1
c ? t : f ==> c & t | ~c & f // (c&(t^f))^f (-1 ops)
a != b ==> a^b
That gives us (13 ops):
sign_x = x >> 31;
sign_y = y >> 31;
sign_xy = sign_x ^ sign_y;
x_minus_y = x + ~y + 1;
sign_x_minus_y = x_minus_y >> 31;
x_lt_y = sign_xy & sign_x | ~sign_xy & sign_x_minus_y;
return !!x_lt_y; // x_lt_y & 1 (-1 ops)
We can further simplify (9 ops) by extracting the ">>31" operation, that is a>>31 # b>>31 == (a # b)>>31 where # is one of &, |, ^:
xy = x ^ y;
x_y = x + ~y + 1;
x_lt_y = (xy & (x ^ x_y)) ^ x_y;
return (x_lt_y>>31) & 1;
All the other comparisons can be obtained as such:
x > y is (y < x)
x <= y is !(y < x)
x >= y is !(x < y)
x == y is !(y<x | x<y)
x != y is !!(y<x | x<y)

Right Rotation of Bits in C

I'm working on exercise 2-8 in K&R which asks us to write function rightrot(int x, int n) such that all bits of x are shifted n times to the right with the bits that fall off the right-end reappearing on the left-end.
Here is my attempted solution in which I shift each bit one-by-one:
int rightrot(int x, int n)
{
int i, rmb;
for(i = 0; i < n; ++i)
{
// get right-most bit
rmb = x & 1;
// shift 1 to right
x = x >> 1;
// if right-most bit is set, set left-most bit
if (rmb == 1)
x = x | (~0 ^ (~0 >> 1) );
}
return x;
}
When I execute rightrot(122, 2), I expect to get 94 since 122 is 1111010 and 94 is 1011110. Instead, I get 30 which happens to be 0011110. Clearly, my method for setting the left-most bit is not working as I expect it to. Does anyone spot an obvious error? I'm just learning about capturing bits and the like.
NOTE: I got the technique for setting the left-most bit from this post.
Let's analyse (~0 ^ (~0 >> 1) ):
~0 is -1
~0 >> 1 is again -1, if the sign bit is 1 rightshift will fill the new bits with 1s.
-1 ^ -1 is 0.
x = x | 0 is x.
The solution is that you should use unsigned datatypes if you want to do bitoperations.
So you should use the line x = x | (~0u ^ (~0u >> 1) );
To avoid other problems the parameter x should also be unsigned int.
https://ideone.com/7zPTQk

simulate jg instruction(datalab's isGreater)

I am doing CSAPP's datalab, the isGreater function.
Here's the description
isGreater - if x > y then return 1, else return 0
Example: isGreater(4,5) = 0, isGreater(5,4) = 1
Legal ops: ! ~ & ^ | + << >>
Max ops: 24
Rating: 3
x and y are both int type.
So i consider to simulate the jg instruction to implement it.Here's my code
int isGreater(int x, int y)
{
int yComplement = ~y + 1;
int minusResult = x + yComplement; // 0xffffffff
int SF = (minusResult >> 31) & 0x1; // 1
int ZF = !minusResult; // 0
int xSign = (x >> 31) & 0x1; // 0
int ySign = (yComplement >> 31) & 0x1; // 1
int OF = !(xSign ^ ySign) & (xSign ^ SF); // 0
return !(OF ^ SF) & !ZF;
}
The jg instruction need SF == OF and ZF == 0.
But it can't pass a special case, that is, x = 0x7fffffff(INT_MAX), y = 0x80000000(INT_MIN).
I deduce it like this:
x + yComplement = 0xffffffff, so SF = 1, ZF = 0, since xSign != ySign, the OF is set to 0.
So, what's wrong with my code, is my OF setting operation wrong?
You're detecting overflow in the addition x + yComplement, rather than in the overall subtraction
-INT_MIN itself overflows in 2's complement; INT_MIN == -INT_MIN. This is the 2's complement anomaly1.
You should be getting fast-positive overflow detection for any negative number (other than INT_MIN) minus INT_MIN. The resulting addition will have signed overflow. e.g. -10 + INT_MIN overflows.
http://teaching.idallen.com/dat2343/10f/notes/040_overflow.txt has a table of input/output signs for add and subtraction. The cases that overflow are where the inputs signs are opposite but the result sign matches y.
SUBTRACTION SIGN BITS (for num1 - num2 = sum)
num1sign num2sign sumsign
---------------------------
0 0 0
0 0 1
0 1 0
*OVER* 0 1 1 (subtracting a negative is the same as adding a positive)
*OVER* 1 0 0 (subtracting a positive is the same as adding a negative)
1 0 1
1 1 0
1 1 1
You could use this directly with the original x and y, and only use yComplement as part of getting the minusResult. Adjust your logic to match this truth table.
Or you could use int ySign = (~y) >> 31; and leave the rest of your code unmodified. (Use a tmp to hold ~y so you only do the operation once, for this and yComplement). The one's complement inverse (~) does not suffer from the 2's complement anomaly.
Footnote 1: sign/magnitude and one's complement have two redundant ways to represent 0, instead of an value with no inverse.
Fun fact: if you make an integer absolute-value function, you should consider the result unsigned to avoid this problem. int can't represent the absolute value of INT_MIN.
Efficiency improvements:
If you use unsigned int, you don't need & 1 after a shift because logical shifts don't sign-extend. (And as a bonus, it would avoid C signed-overflow undefined behaviour in +: http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html).
Then (if you used uint32_t, or sizeof(unsigned) * CHAR_BIT instead of 31) you'd have a safe and portable implementation of 2's complement comparison. (signed shift semantics for negative numbers are implementation-defined in C.) I think you're using C as a sort of pseudo-code for bit operations, and aren't interested in actually writing a portable implementation, and that's fine. The way you're doing things will work on normal compilers on normal CPUs.
Or you can use & 0x80000000 to leave the high bits in place (but then you'd have to left shift your ! result).
It's just the lab's restriction, you can't use unsigned or any constant larger than 0xff(255)
Ok, so you don't have access to logical right shift. Still, you need at most one &1. It's ok to work with numbers where all you care about is the low bit, but where the rest hold garbage.
You eventually do & !ZF, which is either &0 or &1. Thus, any high garbage in OF` is wiped away.
You can also delay the >> 31 until after XORing together two numbers.
This is a fun problem that I want to optimize myself:
// untested, 13 operations
int isGreater_optimized(int x, int y)
{
int not_y = ~y;
int minus_y = not_y + 1;
int sum = x + minus_y;
int x_vs_y = x ^ y; // high bit = 1 if they were opposite signs: OF is possible
int x_vs_sum = x ^ sum; // high bit = 1 if they were opposite signs: OF is possible
int OF = (x_vs_y & x_vs_sum) >> 31; // high bits hold garbage
int SF = sum >> 31;
int non_zero = !!sum; // 0 or 1
return (~(OF ^ SF)) & non_zero; // high garbage is nuked by `& 1`
}
Note the use of ~ instead of ! to invert a value that has high garbage.
It looks like there's still some redundancy in calculating OF separately from SF, but actually the XORing of sum twice doesn't cancel out. x ^ sum is an input for &, and we XOR with sum after that.
We can delay the shifts even later, though, and I found some more optimizations by avoiding an extra inversion. This is 11 operations
// replace 31 with sizeof(int) * CHAR_BIT if you want. #include <limit.h>
// or use int32_t
int isGreater_optimized2(int x, int y)
{
int not_y = ~y;
int minus_y = not_y + 1;
int sum = x + minus_y;
int SF = sum; // value in the high bit, rest are garbage
int x_vs_y = x ^ y; // high bit = 1 if they were opposite signs: OF is possible
int x_vs_sum = x ^ sum; // high bit = 1 if they were opposite signs: OF is possible
int OF = x_vs_y & x_vs_sum; // low bits hold garbage
int less = (OF ^ SF);
int ZF = !sum; // 0 or 1
int le = (less >> 31) & ZF; // clears high garbage
return !le; // jg == jnle
}
I wondered if any compilers might see through this manual compare and optimize it into cmp edi, esi/ setg al, but no such luck :/ I guess that's not a pattern that they look for, because code that could have been written as x > y tends to be written that way :P
But anyway, here's the x86 asm output from gcc and clang on the Godbolt compiler explorer.
Assuming two's complement, INT_MIN's absolute value isn't representable as an int. So, yComplement == y (ie. still negative), and ySign is 1 instead of the desired 0.
You could instead calculate the sign of y like this (changing as little as possible in your code) :
int ySign = !((y >> 31) & 0x1);
For a more detailed analysis, and a more optimal alternative, check Peter Cordes' answer.

Greater than function in 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.

How can I divide a signed integer using only binary operators?

I can only use ! ~ & ^ | + << >>
I am writing this in C.
I am trying to divide a number x by 2^n.
So i thought if I shift x >> n that would work, but it does not work with odd negative integers. It originally looked like this:
int dl18(int x, int n) {
return (x >> n);
}
but if x = -9 and n = 1 the output should be -4 but it is -5.
and if x = -9 and n = 0 the output is correct (-9).
Thanks in advance.
So I figured out doing this makes it work for everything unless n = 0 and x is a negative number:
return (~(x >> 31) & (x >> n)) | ((x >> 31) & ((x >> n) + 1));
Assuming two's complement representation of signed integers and arithmetic shift behaviour of >> operator, the answer could be:
int dl18(int x, int n) {
if (x < 0) {
x += (1 << n) - 1;
}
return x >> n;
}
The addition is necessary, because >> rounds for negative numbers towards negative infinity. By adding 2^n - 1, the result is always truncated towards zero, just like it happens for / operator.
Due to your requirements, assuming that int has 4 bytes (and to be extra pedantic CHAR_BIT = 8), the expression may be rewritten (obfuscated) as:
(x + ((x >> 31) & ((1 << n) + ~0))) >> n
The idea of x >> 31 is to replicate MSB bit, so the mask becomes either all ones (i.e. 0xFFFFFFFF), or all zeros, which is then used to either preserve or eliminate ((1 << n) - 1) from addition. Parentheses around & are necessary, because addition has higher precedence than bitwise AND.
This algorithm is also used by GCC compiler. For instance:
int dl18_4(int x) { return x / 4; }
translates with -O1 into:
dl18_4:
lea eax, [rdi+3] ; eax = rdi + 3
test edi, edi ; set sign flag if edi < 0
cmovns eax, edi ; eax = edi if SF = 0
sar eax, 2 ; eax = eax >> 2
ret
Note that shifting by negative number invokes undefined behavior, so it may be safer to declare second parameter as unsigned int.
Here is a solution that avoids bit-shifting negative values. It does assume twos-complement representation, but it does not use the unary negative operator.
A bitmask is used to set neg to a non-zero value if x is negative, or to zero if x is non-negative. Here a trick suggested by #Grzegorz Szpetkowski is used to avoid subtraction by 1: adding ~0 instead. If x is negative, the value of x is changed to the magnitude of x. To avoid using the unary negative here, using a trick suggested by #chux, we take advantage of the fact that for a negative value in twos-complement, the corresponding positive value is equal to the bitwise negation of the negative representation plus 1.
This magnitude of x can be bit-shifted without encountering implementation-dependent behavior. After performing the division, the result is converted back to a negative value if the original value was negative, by performing the same transformation as before.
#include <stdio.h>
#include <limits.h>
int divide_2n(int x, unsigned n);
int main(void)
{
printf("-7 / 4 = %d\n", divide_2n(-7, 2));
printf("27 / 8 = %d\n", divide_2n(27, 3));
printf("-27 / 8 = %d\n", divide_2n(-27, 3));
printf("-9 / 2 = %d\n", divide_2n(-9, 1));
printf("-9 / 1 = %d\n", divide_2n(-9, 0));
return 0;
}
int divide_2n(int x, unsigned n)
{
unsigned n_bits = CHAR_BIT * sizeof(int);
unsigned neg = x & (1U << (n_bits + ~0));
if (neg) {
x = ~(unsigned)x + 1;
}
x = (unsigned)x >> n;
if (neg) {
x = ~x + 1;
}
return x;
}
-7 / 4 = -1
27 / 8 = 3
-27 / 8 = -3
-9 / 2 = -4
-9 / 1 = -9

Resources