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.
Related
This is what I've found so far online,
int main(void)
{
long a = 12345;
int b = 10;
int remain = a - (a / b) * b;
printf("%i\n", remain);
}
First I wonder how the formula works. Maybe i cant do math, but the priority of operations here seems a bit odd. If i run this code the expected answer of 5 is printed. But I dont get how (a / b) * b doesn't cancel out to 'a' leading to a - a = 0.
Now, this only works for int and long, as soon as double are involved it doesn't work anymore. Anyone might tell me why? Is there an alternative to modulo that works for double?
Also I'm not sure if i understand up to what value a long can go, i found online that the upper limit was 2147483647 but when i input bigger numbers such as the one in 'a' the code runs without any issue up to a certain point...
Thanks for your help I'm new to coding and trying to learn!
Given two double finite numbers x and y, with y not equal to zero, fmod(x, y) produces the remainder of x when divided by y. Specifically, it returns x − ny, where n is chosen so that x − ny has the same sign as x and is smaller in magnitude than y. (So, if x is positive, 0 ≤ fmod(x, y) < x, and, if x is negative, x < fmod(x, y) ≤ 0.)
fmod is declared in <math.h>.
A properly implemented fmod returns an exact result; there is no floating-point error, since the specified result is always representable.
The C standard also specifies remquo to return the remainder and some low bits (at least three) of the quotient n and remainder with a variation on the definition of the remainder. It also specifies variants of these functions for float and long double.
Naive implementation. Limited range. Adds additional floating point imprecisions (as it does some arithmetic)
double naivemod(double x)
{
return x - (long long)x;
}
int main(void)
{
printf("%.50f\n", naivemod(345345.567567756));
printf("%.50f\n", naivemod(.0));
printf("%.50f\n", naivemod(10.5));
printf("%.50f\n", naivemod(-10.0/3));
}
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
In the following code, x and y are int32_t variables. In this simplified example, they always differ by 1. When they span the int32_t overflow boundary (0x7FFFFFFF, the max 2's compliment 32-bit positive number, to 0x80000000, the largest magnitude negative number), subtracting them seems to give different results when it is done inside the conditional of the if statement (Method 1) than it does if the result is stored in a temporary variable (Method 2). Why don't they give the same result?
I would think that subtracting two int32_t variables would yield a result of type int32_t, so using a temporary of that type shouldn't change anything. I tried explicitly typecasting inside the if statement conditional; that didn't change anything. FWIW, Method 2 gives the result I would expect.
The code:
int32_t x = (0x80000000 - 3);
int i;
for( i = 0; i < 5; ++i )
{
int32_t y = x + 1; // this may cause rollover from 0x7fffffff (positive) to 0x80000000 (negative)
UARTprintf("\n" "x = 0x%08X, y = 0x%08X", x, y );
if( ( y - x ) >= 1 ) // Method 1
UARTprintf(" - true ");
else
UARTprintf(" - FALSE");
int32_t z = ( y - x ); // Method 2
if( ( z ) >= 1 )
UARTprintf(" - true ");
else
UARTprintf(" - false");
++x;
}
Output:
x = 0x7ffffffd, y = 0x7ffffffe - true - true
x = 0x7ffffffe, y = 0x7fffffff - true - true
x = 0x7fffffff, y = 0x80000000 - FALSE - true
x = 0x80000000, y = 0x80000001 - true - true
x = 0x80000001, y = 0x80000002 - true - true
In my actual application (not this simplified example), y is incremented by a hardware timer and x is a record of when some code was last executed. The test is intended to make some code run at intervals. Considering that y represents time and the application may run for a very long time before it is restarted, just not letting it overflow isn't an option.
Noting, as several of you did, that the standard does not define the behavior when signed integer overflow occurs tells me that I don't have a right to complain that I can't count on it working the way I want it to, but it doesn't give me a solution I can count on. Even using a temporary variable, which seems to work with my current compiler version and settings, might quit working when one of those things changes. Do I have any trustworthy options short of resorting to assembly code?
Given that signed integer overflow leads to undefined behaviour - you better not try to explain it.
Because your assumptions are based on "common sense", not the standard.
Otherwise - check assembly and try to debug it, but again, the outcome would not be scalable: you won't be able to apply the new knowledge to some other case (but with no doubt it would be fun to do).
The question I didn't know enough to ask originally is, "How can I avoid undefined behavior when doing subtraction on integers that might have overflowed?" Please correct me if I am wrong, but it appears that the answer to that question would be "use unsigned rather than signed integers" because the results are well defined (per C11 6.2.5/9) "a result that cannot be represented by the resulting unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the resulting type."
In this case, that is enough to come up with a working solution because the elapsed time will always be zero or a small positive number therefore the result of the subtraction will always be positive. So the result of the subtraction could be kept as an unsigned number and compared ( ">=1" ) or converted back to a signed int for comparison (C11 6.3.1.3 "When a value with integer type is converted to another integer type ... if the value can be represented by the new type, it is unchanged." This code works, and I believe does not rely on any undefined behavior: "if( ( (int32_t)(uint32_t)y - (uint32_t)x ) >= 1 )"
In the more general case, however, converting to unsigned to do the subtraction, then converting back to a signed result (which might be negative) is not well defined. C11 6.3.1.3 says regarding converting to another integer type that if "the new type is signed and the value cannot be represented in it; either the result is implementation-defined or an implementation-defined signal is raised." So I can still imagine a scenario in which assembly code would be needed to achieve well-defined results; this just isn't one of them.
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.
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!