I was reading about why the following code is buggy:
int tadd_ok ( int x, int y ) {
int sum = x + y;
return ( sum - x == y ) && ( sum - y == x );
}
The explanation was that two's complement addition forms an abelian group and so the expression
(x + y) - x with evaluate to y regardless if whether or not the addition overflows.
(Same for (x + y) - y) which will evaluate to x).
I don't understand this explanation or the abelian group reference. Two's complement addition is basically unsigned modulo arithmetic that is "converted" to two's complement, right?
So for example if we have 4 bits we have the range [-8, 7].
In the example if we had x = 7 and y = 6 the result overflows to 6. And that is not equal to either y or x.
So why is the explanation that the equality is always valid regardless of the overflow?
An "abelian" group just means that the order that you add things doesn't matter - (a+b)+c = a+(b+c) and (a+b) == (b+a).
This is true of the integers in C. It is technically true as #ouah points out that overflow is undefined, but this is to support the C standard easily on processors that do not use two's compliment math. Most do.
On those, unless something very strange (or not so strange, but optimized - thanks #ouah) is going on in the compiler, unsigned math will function as an abelian group.
In your example, 7+6 = 0111 + 0110 == 1101 is -(0010+1) = -3. Negative numbers "count downward" in binary in a twos' complement signed system: 1111 is -1. Subtracting back yields 1010, or 0101+1 = 6.
This is the old question, but hope my answer will be useful for someone.
This is because to fix a positive overflow (when x + y > TYPE_MAX) we need to subtract 2^n from the sum and to fix a negative one (when x + y < TYPE_MIN) we need to add 2^n (a bunch of math statements are needed to show this, so I decided not to include them in the answer).
Therefore if x + y is positively overflowed sum actually equals to x + y - 2^n. After this when we perform comparison we subtract x from sum which causes a negative overflow and hence we have sum - x actually equals to sum - x + 2^n. Thus, sum - x + 2^n = x + y - 2^n - x + 2^n = x. The same happens with another preposition.
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
Title basically says it all. My friend gave me this as a challenge he solved in some CTF he is doing. I have thought about it for a while and can not figure it out. Also, INFINITY isn't a valid answer. Thanks.
The only way this happens in C is:
x is an infinity (+∞ or −∞) (equivalently, HUGE_VAL or -HUGE_VAL in implementations that do not support infinities).
x is a NaN and the C implementation uses non-IEEE-754 behavior for NaNs.
x is adjacent to an infinity in the floating-point representation and a suitable directed rounding mode is used.
x+1 and x*2 overflow and the resulting behavior not defined by the C standard happens to report the comparisons as true.
x is uninitialized and hence indeterminate and takes on different values in the two appearances of x in x+1 == x such that the comparison is true and, in x*2 == x either similarly takes on different values or takes on the value zero.
x is uninitialized and has automatic storage duration and its address is not taken, and hence the behavior is not defined by the C standard, and the resulting behavior happens to report the comparisons as true.
Proof:
Other than infinity, the statements are mathematically false in real numbers, and therefore this cannot arise from real-number behavior. So it must arise from some non-real-number behavior such as overflow, wrapping, rounding, indeterminate values (which may be different in each use of an object) or uninitialized values. Since * is constrained to have arithmetic operands, we only need to consider arithmetic types. (In C++, one could define a class to make the comparisons true.)
For signed integers, non-real-number behavior with fully defined values occurs for + and * only when there is overflow, so that is a possibility.
For unsigned integers, non-real-number behavior with fully defined values occurs for + and * only when there is wrapping. Then, with wrapping modulo M, we would have x+1 = x+kM for some integer k, so 1 = kM, which is not possible for any M used in wrapping.
For the _Bool type, exhaustive testing of the possible values eliminates them.
For floating-point numbers, non-real-number behavior with fully defined values occurs for + and * only with rounding, underflow, and overflow and with NaNs. NaNs never compare as equal by IEEE-754 rules, so they cannot satisfy this, except for the fact that the C standard does not require IEEE-754 conformance, so an implementation could choose to make the comparisons true.
x*2 will not underflow, since it increases the magnitude. x+1 can be made to underflow in a perverse floating-point format with smaller exponent range than precision, but this will not produce x+1 == x. x+1 == x can be satisfied by rounding for sufficiently large x, but then x*2 must produce a value other than x.
That leaves overflow. If x is the greatest representable finite number (and hence the greatest representable number less than infinity), and the rounding mode is downward (toward −∞) or toward zero, then x+1 will yield x and x*2 will yield x, so the comparisons yield true. Similarly, the greatest negative representable finite number will satisfy the comparisons with rounding upward (toward +∞) or toward zero.
The equalities will hold true for double x = HUGE_VAL;. Since C99, quoting cppreference.com:
The HUGE_VALF, HUGE_VAL and HUGE_VALL macros expand to positive floating point constant expressions which compare equal to the values returned by floating-point functions and operators in case of overflow
Sample code:
#include <math.h>
#include <stdio.h>
int main() {
double x = HUGE_VAL;
printf("%d %d\n", x + 1 == x, 2 * x == x);
return 0;
}
Output:
1 1
Solving for x using the C preprocessor:
#include <stdio.h>
int main() {
#define x 1,1
if (x + 1 == x)
printf("x + 1 == x is true\n");
if (x * 2 == x)
printf("x * 2 == x is true\n");
printf("x = %d\n", x);
printf("x + 1 = %d\n", x + 1);
printf("x * 2 = %d\n", x * 2);
return 0;
}
Output (warnings omitted :):
x + 1 == x is true
x * 2 == x is true
x = 1
x + 1 = 1
x * 2 = 1
Given three variables:
int x = rand();
int y = rand();
int z = x + y;
Is it always true that z + (~x + 1) is equal to y. Or is there a possible overflow that makes the result not equal to y?
In twos-complement signed arithmetic with wraparound, (~x + 1) is equal to -x, so z + (~x + 1) is equal to z - x is equal to y, no matter what the original values of x and y were.
There are two possible reasons why a C implementation might not use twos-complement signed arithmetic with wraparound.
The C standard still provides, in principle, for the possibility that the CPU doesn't use a twos-complement representation of negative numbers. This is unlikely to be relevant nowadays: the UNIVAC is the only example I know of that's still in production, and I'm actually surprised to discover that it is still in production.
The C standard says that signed overflow has undefined behavior. That means the compiler is allowed to assume it never happens, and generate code that will produce arbitrarily nonsensical output (or even crash) if either addition overflows. This is likely to be relevant.
You can avoid both of these possibilities by declaring x, y, and z to be unsigned int instead of int. Then y + x + (~x + 1) is guaranteed to equal y.
How do we write a program in C which can calculate an average of 2 16 bit signed numbers on a 16 bit processor.
int getAverage(int x, int y)
{
int result=0;
result = ((x+y)/2);
return result;
}
The above works for most cases except for when both x and y are max values 65535.
In the case where both x and y are positive or negative numbers, I would divide the difference between the numbers by 2 and add that result to the number that is subtracted. Mathematically, this is equivalent to what you currently have:
(y - x)/2 + x = y/2 - x/2 + x = y/2 + x/2 = (x + y)/2
If x is positive and y is negative or vice versa, the original method of calculation that you have should be used.
Simplest possible solution with some crude integer rounding:
int32_t getAverage (int16_t x, int16_t y)
{
int32_t sum = (int32_t)x + (int32_t)y;
return sum/2 + sum%2;
}
This will work just fine since your 16 bit compiler will have software routines to handle 32 bit integers.
I'm just starting to learn C at school, I'm trying to get a hold of the basic concepts.
Our homework has a question,
for every int x: x+1 > x
Determine whether true or false, give reasoning if true and counterexample if false.
I'm confused because we were taught that the type int is of 32-bits and basically that means the integer is in binary format. Is x+1 adding 1 to the decimal value of 1?
x + 1 > x
is 1 for every int value except for value INT_MAX where INT_MAX + 1 is an overflow and therefore x + 1 > x expression is undefined behavior for x value of INT_MAX.
This actually means a compiler has the right to optimize out the expression:
x + 1 > x
by
1
As INT_MAX + 1 is undefined behavior, the compiler has the right to say that for this specific > expression INT_MAX + 1 is > INT_MAX.
As the x + 1 > x expression is undefined behavior for x == INT_MAX, it is also not safe to assume x + 1 > x can be false (0).
Note that if x was declared as an unsigned int instead of an int the situation is completely different. unsigned int operands never overflow (they wrap around): UINT_MAX + 1 == 0 and therefore x + 1 > x is 0 for x == UINT_MAX and 1 for all the other x values.
Modern compilers (like gcc) usually take the opportunity to optimize this expression and replace it with 1.
For the record, there was some serious security issues with known server programs using code like:
if (ptr + offset < ptr)
The code was meant to trigger a safety condition but the compiler would optimize out the if statement (by replacing the expression with 0) and it allowed an attacker to gain privilege escalation in the server program (by opening the possibility of an exploitable buffer overflow if I remember correctly).
Note for 32-bit number range is [-2147483648, 2147483647] that is equals to [-231, 231 -1 ].
So for expression x+1 > x is true for [-2147483648, 2147483646]
But not for 2147483647 because adding to 2147483647 in 32-bit size number causes bit overflow many implementations it makes x + 1 to -2147483648 But really behavior is
Undefined in C standard.
So,
x + 1 > x True for x in [-2147483648, 2147483646] only
x + 1 > x , for x = 2147483647 is Undefined value may be True or False depends on compiler. If a compiler calculates = -2147483648 value will be False.
I don't want to hand you the answer, so I'll reply with a question that should get you on the right track.
What is x + 1 when x is the largest possible value that can be stored in a 32-bit signed integer? (2,147,483,647)
Yes, x + 1 adds to the decimal value of 1.
This will be true almost all of the time. But if you add 1 to INT_MAX (which is 215 - 1 or greater), you might flip the sign. Think about the decimal representation of 0111111 versus 11111111. (Obviously not 32 bits, but the ideas hold.)
Look up two's complement if you're confused about why it flips. It's a pretty clever implementation of integers that makes addition easy.
EDIT: INT_MAX + 1 is undefined behavior. Doesn't necessarily become INT_MIN. But since x + 1 is not necessarily > x when x == INT_MAX, then the answer is clearly false!
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