Warning C26451: Arithmetic overflow (when subtracting two ints) - c++

When performing the following line of code:
int max = 50, min = -30;
double num = rand() % (max - min) - min;
I get the following warning from Visual Studio 2019:
Warning C26451 Arithmetic overflow: Using operator '-' on a 4 byte value and then casting the result to a 8 byte value. Cast the value to the wider type before calling operator '-' to avoid overflow (io.2).
I'm not sure how this is applicable, as I am taking the modulus of a double, which will return and integer, and then subtracting another integer from it, before storing it in a double (which I'm fairly certain isn't the problem).
Is this a bug or am I doing something that could result in truncation etc.?
Thanks

The difference (in both of subtractions) can result in overflow. The overflow may happen if you subtract negative values from positive, or positive values from negative.
For example, if you subtract something negative from a maximum possible value, you'll get an overflow.
As you have wider destination type, it is possible that you intend this wider result to fit this wider type without overflow. This will not happen, unless you cast one of your operands.
I don't think it is practical to do such cast here, as you use % operator, this will not work with double. And anyway it will not handle overflow, just because you cannot have more range here than range of rand().
Apparently if you want to fix the possible overflow of rand(), you'll need std::uniform_int_distribution with your range. This would fix other rand() problems along (thread safety and not good randomness), but would add a bit of complexity as well.
But sure if you always have -30 to 50 range, there's no overflow, and you can treat it as a false warning. If you literally have int max = 50, min = -30; I even see it as a bug of static analysis to emit this warning. Sure static analysis cannot predict the result of rand(), but there's % to truncate it. Maybe use Help > Send Feedback > Report a problem if you care.

Related

Remainder of a division with c++ getting 'Stack Overflow' exception [duplicate]

This question already has answers here:
Why does floating-point arithmetic not give exact results when adding decimal fractions?
(31 answers)
Closed 3 years ago.
I'm trying to understand some concepts in C++, and I made this code to get the remainder of a division (like % operator):
double resto(double a, double b) {
if (a == b) return 0;
else if (a < b) return a;
else {
return resto(a-b, b);
}
}
When I run it with lowers numbers like (12,3) or (2,3), it runs fine.
But if I try to run it with the parameters (2147483647 * 1024, 3) I get:
Stack overflow (parameters: 0x0000000000000001, 0x000000F404403F20)
As I'm new in C++, I'm not sure if it's something with Visual Studio 2017 or it's the compiler, or stack memory, etc.
resto(2147483647 * 1024, 3);
is going to recurse 2147483647 * 1024 / 3, or about 733 billion, times. Every recursive call is using a small amount of Automatic storage for parameters and book-keeping and the program will likely run out of storage before it reaches even a million iterations.
For this you will have to use a loop or smarter logic (for example subtracting larger multiples of b until using smaller numbers begins to make sense), but fmod is probably going to be faster and more effective.
Other notes:
2147483647 * 1024
is an integer times an integer. This math will take place in ints and overflow if int is 16 or 32 bit on your system. Exactly what happens when you overflow a signed integer is undefined, but typically the number does a 2s compliment wrap-around (to -1024 assuming 32 bit integer). More details on overflowing integers in Is signed integer overflow still undefined behavior in C++?. Use
2147483647.0 * 1024
to force floating point numbers.
Also watch out for Is floating point math broken? Floating point is imprecise and it's often difficult to get to floating point numbers that should be the same to actually be the same. a == b is often false when you expect true. In addition if one number gets too much larger than the other a-b may have no visible effect because b is lost in the noise at the end of a. The difference between the two cannot be represented correctly.

why do I get different results with the same conditions in a for loop?

I was stuck when I was trying to use a for loop to solve a problem.
Here's my simplified code:
int main(int argc, const char * argv[])
{
std::vector<int> a;
a.push_back(2333);
int n = 10, m = 10;
for(int i=0; i< -1; i++)
m--;
std::cout<<m<<endl;
for(int j=0; j<a.size()-2; j++)
n--;
std::cout<<n<<endl;
return 0;
}
Apparently, a.size() = 1 so these two end conditions should be the same. However, when I ran my code on Xcode 9.4.1 I got unexpected as it turned out that m = 10
and n = 11. And I found that the time it took to get the value of n is much longer than m.
Why would I get such a result? Any help will be appreciated.
The value returned by size() is std::size_t, which is an unsigned integral type. This means that it can only represent non-negative numbers, and if you do an operation that results in a negative number, it will wrap around to the largest possible value like in modular arithmetic.
Here, 2 - 1 is -1, which wraps to 2^32 - 1 on a 32-bit system. When you try to subtract 2^32 - 1 from 10, you cause a signed integer underflow since the minimum value of a 32-bit integer is -2^31. Signed integer overflow/underflow is undefined behavior, so anything can happen.
In this case, it seems like the underflow wrapped around to the maximum value. So the result would be 10 - (2^32 - 1) + 2^32, which is 11. We add 2^32 to simulate the underflow wrapping around. In other words, after the 2^31 + 10th iteration of the loop, n is the minimum possible value in a 32-bit integer. The next iteration causes the wrap around, so n is now 2^31 - 1. Then, the remaining 2^31 - 12 iterations decrease n to 11.
Again, signed integer overflow/underflow is undefined behavior, so don't be surprised when something weird happens because of that, especially with modern compiler optimizations. For example, your entire program can be "optimized" to do absolutely nothing since it will always invoke UB. You're not even guaranteed to see the output from std::cout<<m<<endl;, even though the UB is invoked after that line executes.
The value returned by a.size() is it type size_t, which is an unsigned int, because there wouldn’t be any reason to have a size that is negative. If you do 1-2 with unsigned numbers it will roll over and become a value near the maximum value for an unsigned int and the loop will take quite a while to run, or might not even stop since a signed integer can’t be larger than the top half of unsigned values. This depends on the rules of comparing signed and unsigned which I don’t remember for sure on the spot.
Using a debugger and making sure the types are correct (your compiler should mention signed/unsigned mismatch here) helps determine these cases.

Compile-time calculation of bits needed to represent a range

I need to calculate at compile-time the number of bits needed to represent a range.
For an unsigned range from 0 to n it is simple:
constexpr unsigned bits_to_represent(uintmax_t n)
{
return n > 0
? 1 + bits_to_represent(n/2)
: 0;
}
For a signed range, I have:
constexpr unsigned bits_in_range(intmax_t min,intmax_t max)
{
return bits_to_represent(max >= 0
? static_cast<uintmax_t>(max) - min
: max - min);
}
However this causes MSVC 2015 (recently updated) to complain:
warning C4308: negative integral constant converted to unsigned type
Can you explain why this happens? As a work-around, I static_cast min to uintmax_t, but I do not like this solution as it seems less portable than my preferred solution and probably even is undefined behaviour, even though I am sceptical is that can happen at compile time.
I'm not sure exactly why MSVC is giving a warning, but one thing that you are doing that could cause bad behavior is mixing signed and unsigned integers in arithmetic operations and comparisons.
You can read this for examples of problems caused by this: http://blog.regehr.org/archives/268
I would try rewriting your function like this:
constexpr unsigned bits_in_range(intmax_t min,intmax_t max)
{
return bits_to_represent(
static_cast<uintmax_t>(max) - static_cast<uintmax_t>(min));
}
This way is more programmer friendly. When you do arithmetic operations on mismatched integer types, the compiler is going to have to do implicit conversions to make them match. This way, it doesn't have to do that. Even if max and min are negative, this will still give well-defined and correct results, if you are sure that max >= min.
Do it in 4 parts. Each of min max at least zero.
If they share the same sign (with 0 as positive), 2s complement integers can have their difference represented as part of their own type.
That leaves max<min and max positive and min negative cases.
If we assume uint_max_t is big enough, arithmetic and conversion to that type all behaves according to math mod 2^n.
So unsigned(a)-unsigned(b) will actually be the unsigned distance to get from b to a as signed integers.
C = A-B mod X
C = A-B + kX
B+C=A+kX
With C positive and less than X, and X larger than B-A, gives us C must be the delta.
Thank you for your comments even though they did not explain the Microsoft warning. Clang compiles cleanly, so it might be a bug in the compiler.
Due to the nature of conversion from signed to unsigned values in C++ the correct answer will be obtained by simply casting both values (again assuming that min <= max):
constexpr unsigned bits_in_range(intmax_t min,intmax_t max)
{
return bits_to_represent(static_cast<largest_uint>(max) -
static_cast<largest_uint>(min));
}
The validity of the code can be inferred from this part of the draft standard (I looked at the newest draft but am confident that there has not been a change here).
4.7 Integral conversions [conv.integral]
If the destination type is unsigned, the resulting value is the least > unsigned integer congruent to the source
integer (modulo 2n where n is the number of bits used to represent the
unsigned type).

Acting like unsigned int overflow. What is causing it?

I have this function which generates a specified number of so called 'triangle numbers'. If I print out the deque afterwords, the numbers increase, jumps down, then increases again. Triangle numbers should never get lower as i rises so there must be some kind of overflow happening. I tried to fix it by adding the line if(toPush > INT_MAX) return i - 1; to try to stop the function from generating more numbers (and return the number it generated) if the result is overflowing. That is not working however, the output continues to be incorrect (increases for a while, jumps down to a lower number, then increases again). The line I added doesn't actually seem to be doing anything at all. Return is not being reached. Does anyone know what's going on here?
#include <iostream>
#include <deque>
#include <climits>
int generateTriangleNumbers(std::deque<unsigned int> &triangleNumbers, unsigned int generateCount) {
for(unsigned int i = 1; i <= generateCount; i++) {
unsigned int toPush = (i * (i + 1)) / 2;
if(toPush > INT_MAX) return i - 1;
triangleNumbers.push_back(toPush);
}
return generateCount;
}
INT_MAX is the maximum value of signed int. It's about half the maximum value of unsigned int (UINT_MAX). Your calculation of toPush may well get much higher than UINT_MAX because you square the value (if it's near INT_MAX the result will be much larger than UINT_MAX that your toPush can hold). In this case the toPush wraps around and results in smaller value than previous one.
First of all, your comparison to INT_MAX is flawed since your type is unsigned int, not signed int. Secondly, even a comparison to UINT_MAX would be incorrect since it implies that toPush (the left operand of the comparison expression) can hold a value above it's maximum - and that's not possible. The correct way would be to compare your generated number with the previous one. If it's lower, you know you have got an overflow and you should stop.
Additionally, you may want to use types that can hold a larger range of values (such as unsigned long long).
The 92682th triangle number is already greater than UINT32_MAX. But the culprit here is much earlier, in the computation of i * (i + 1). There, the calculation overflows for the 65536th triangular number. If we ask Python with its native bignum support:
>>> 2**16 * (2**16+1) > 0xffffffff
True
Oops. Then if you inspect your stored numbers, you will see your sequence dropping back to low values. To attempt to emulate what the Standard says about the behaviour of this case, in Python:
>>> (int(2**16 * (2**16+1)) % 0xffffffff) >> 1
32768
and that is the value you will see for the 65536th triangular number, which is incorrect.
One way to detect overflow here is ensure that the sequence of numbers you generate is monotonic; that is, if the Nth triangle number generated is strictly greater than the (N-1)th triangle number.
To avoid overflow, you can use 64-bit variables to both generate & store them, or use a big number library if you need a large amount of triangle numbers.
In Visual C++ int (and of course unsigned int) is 32 bits even on 64-bit computers.
Either use unsigned long long or uint64_t to use a 64-bit value.

Binary Addition without overflow wrap-around in C/C++

I know that when overflow occurs in C/C++, normal behavior is to wrap-around. For example, INT_MAX+1 is an overflow.
Is possible to modify this behavior, so binary addition takes place as normal addition and there is no wraparound at the end of addition operation ?
Some Code so this would make sense. Basically, this is one bit (full) added, it adds bit by bit in 32
int adder(int x, int y)
{
int sum;
for (int i = 0; i < 31; i++)
{
sum = x ^ y;
int carry = x & y;
x = sum;
y = carry << 1;
}
return sum;
}
If I try to adder(INT_MAX, 1); it actually overflows, even though, I amn't using + operator.
Thanks !
Overflow means that the result of an addition would exceed std::numeric_limits<int>::max() (back in C days, we used INT_MAX). Performing such an addition results in undefined behavior. The machine could crash and still comply with the C++ standard. Although you're more likely to get INT_MIN as a result, there's really no advantage to depending on any result at all.
The solution is to perform subtraction instead of addition, to prevent overflow and take a special case:
if ( number > std::numeric_limits< int >::max() - 1 ) { // ie number + 1 > max
// fix things so "normal" math happens, in this case saturation.
} else {
++ number;
}
Without knowing the desired result, I can't be more specific about the it. The performance impact should be minimal, as a rarely-taken branch can usually be retired in parallel with subsequent instructions without delaying them.
Edit: To simply do math without worrying about overflow or handling it yourself, use a bignum library such as GMP. It's quite portable, and usually the best on any given platform. It has C and C++ interfaces. Do not write your own assembly. The result would be unportable, suboptimal, and the interface would be your responsibility!
No, you have to add them manually to check for overflow.
What do you want the result of INT_MAX + 1 to be? You can only fit INT_MAX into an int, so if you add one to it, the result is not going to be one greater. (Edit: On common platforms such as x86 it is going to wrap to the largest negative number: -(INT_MAX+1). The only way to get bigger numbers is to use a larger variable.
Assuming int is 4-bytes (as is typical on x86 compilers) and you are executing an add instruction (in 32-bit mode), the destination register simply does overflow -- it is out of bits and can't hold a larger value. It is a limitation of the hardware.
To get around this, you can hand-code, or use an aribitrarily-sized integer library that does the following:
First perform a normal add instruction on the lowest-order words. If overflow occurs, the Carry flag is set.
For each increasingly-higher-order word, use the adc instruction, which adds the two operands as usual, but takes into account the value of the Carry flag (as a value of 1.)
You can see this for a 64-bit value here.