I'm using Visual Studio 2017 and C#.
When I run this for loop, it iterates beyond 0, and i becomes 4294967295
//where loActionList.Count starts at 1
// First time through loop works
// Second time I can see i decrement to 4294967295
// I'm declaring i as uint because loActionList requires it
// and because other vars require it (they are based on an external API)
for (uint i = loActionList.Count - 1; i >= 0; i--)
{
....
}
I can do this:
for (int i = (int)loActionList.Count - 1; i >= 0; i--)
{
IPXC_Action_Goto myvar = (IPXC_Action_Goto)loActionList[(uint)i];
}
...but I'd like to know if there is another way to handle this.
Perhaps something that simply prevents the for loop from going beyond 0?
RESOLVED: I ended up using #RonBeyer's suggestion of adding a break with this code if (i == 0) break;.
To understand the issue, lets look at a for loop with a regular int:
int i;
for(i = 5; i >= 0; i--) {
Console.Write(i);
}
Running that, you'd get 543210 as you'd expect.
However, if you output i now, you'd get -1. It stopped, because after making i = -1, it checked -1 >= 0, and then saw that was false and aborted.
The problem with uint (unsigned integer) is that 0 - 1 on a uint give you its max value, since it wraps back around. After doing 0 - 1, it'll check that and see BIG_NUMBER_HERE >= 0 is true, so it'll keep going.
There are a couple simple ways to avoid this. Which you use depends on your use case / personal tastes:
use an int instead of a uint
increase your start value by 1 and end at > 0 instead
make your condition i >= 0 && i < BIG_NUMBER_HERE
Add if (i == 0) break; at the end of the for loop to force out if you've hit zero (thanks Ron Beyer).
The BIG_NUMBER_HERE would be the uint max value. It differs here and there how you get that number, but there should be a constant that will give you that number if you need it.
If you are having issues with sign, but need the cardinality of a uint, I suggest going with long.
If the API requires a particular data type such as uint, I would cast it for each call, to minimize the damage to your code.
for (var i = loActionList.LongCount() - 1; i >= 0; i--)
{
IPXC_Action_Goto myvar = (IPXC_Action_Goto)loActionList[(uint)i];
}
Related
The if code gives correct result but the else portion gives output: 3,2,1,0 and I expecting 6,5,4,3,2,1,0 result.
uint counter = 0;
private void getting_Next_Pic()
{
if(next == true)// Here "**next**" is boolean variable
{
counter = ++counter % 7; // Getting the next pic, Flow in Forward Direction
}
else
{
counter = counter-- % 7; // Getting the previous pic, Flow in Reverse Direction
}
}
The % operator is the remainder operator. It produces the remainder of the division of the operands (the result is negative when the left-hand operand is negative).
The decrement operator when applied to a uint value of 0 results in the positive value 4,294,967,295. The remainder of dividing that number by 7 is 3 (613,566,756 times 7 is 4,294,967,292, which is 3 less than uint.MaxValue, i.e. 4,294,967,295).
In other words, the code's doing exactly what you told it to. You can't rely on the remainder operator to handle your scenario, not when the data type you're using is unsigned.
Note that this would work:
uint counter = 0;
private void getting_Next_Pic()
{
if(next == true)// Here "**next**" is boolean variable
{
counter = (counter + 1) % 7; // Getting the next pic, Flow in Forward Direction
}
else
{
counter = (counter + 6) % 7; // Getting the previous pic, Flow in Reverse Direction
}
}
Adding 6 is the same as subtracting 1 modulus 7.
All that said, I prefer not using the remainder operator for this sort of thing. There is really no need for tricky code, or even trying to optimize performance (even assuming the remainder operator did that, which in most cases it does not). IMHO it's better to just do the actual range checking that you actually care about:
int counter = 0;
private void getting_Next_Pic()
{
counter += next ? 1 : -1;
if (counter < 0)
{
counter = 6;
}
else if (counter > 6)
{
counter = 0;
}
}
Then when you read the code, it actually says exactly what it's doing. It's easy to verify it's correct, and won't confuse you or anyone else trying to figure it out again later.
So I've been trying to write a program in C# that returns all factors for a given number (I will implement user input later). The program looks as follows:
//Number to divide
long num = 600851475143;
//initializes list
List<long> list = new List<long>();
//Defines combined variable for later output
var combined = string.Join(", ", list);
for (int i = 1; i < num; i++)
{
if (num % i == 0)
{
list.Add(i);
Console.WriteLine(i);
}
}
However, after some time the program starts to also try to divide negative numbers, which after some time ends in a System.DivideByZeroException. It's not clear to me why it does this. It only starts to do this after the "num" variable contains a number with 11 digits or more. But since I need such a high number, a fix or similiar would be highly appreciated. I am still a beginner.
Thank you!
I strongly suspect the problem is integer overflow. num is a 64-bit integer, whereas i is a 32-bit integer. If num is more than int.MaxValue, then as you increment i it will end up overflowing back to negative values and then eventually 0... at which point num % i will throw.
The simplest option is just to change i to be a long instead:
for (long i = 1; i < num; i++)
It's unfortunate that there'd be no warning in your original code - i is promoted to long where it needs to be, because there's an implicit conversion from int to long. It's not obvious to me what would need to change for this to be spotted in the language itself. It would be simpler for a Roslyn analyzer to notice this sort of problem.
If I'd like to loop over all long's range, I would ingenually do:
for (long i = long.MinValue; i <= long.MaxValue; ++i)
{
// Do something
}
But it loops forever!
For example, if I do:
for (byte b = byte.MinValue; b <= byte.MaxValue; ++b)
{
// Do something
}
It loops forever too, but I solved like this:
for (int i = byte.MinValue; i <= byte.MaxValue; ++i)
{
byte b = Convert.ToByte(i);
// Do something
}
With long type how can I do?
With long type how can I achieve the same if I don't increment by 1, but of an higher distance?
Are those "ideas" to loop over a type range correct, are there some issues to be warned about, or can I do it better?
In your first two examples, the loop continues forever due to number range overflows.
When i (1st example) or b (2nd example) exceed the maximum value that can be stored in long (1st example) or byte (2nd example), their value overflows to the smallest value storable by that type and the loop starts over and over.
Remember: in a for-loop, first the loop condition is checked, then the counter increments. If the counter overflows during the increment, the subsequent loop condition check still evaluates to true.
To get your example working, try:
for (long i = long.MinValue; ; i++)
{
if (i == long.MaxValue)
{
break;
}
}
If you want to increment in larger steps, try:
const long step = 90000000000;
for (long i = long.MinValue; i <= long.MaxValue; )
{
// check if loop counter overflows when incrementing by the step
if (unchecked (i + step) < i)
{
break;
}
// otherwise it is safe to increment it
else
{
i += step;
}
}
This is caused by integer overflow when you try to increment past MaxValue. You could try this instead:
long i = long.MinValue;
do
{
// Do something
} while (i++ != long.MaxValue);
This way, the value of i is checked before it's incremented, and the loop terminates correctly.
You could use BigInteger to keep your loop pattern the same and avoid the overflow:
for (BigInteger i = long.MinValue; i <= long.MaxValue; ++i)
{
// Do something
}
I haven't benchmarked it, but I would imagine there would be a noticeable performance penalty for doing it this way.
I'm trying to understand why I can't print only the members of a subsequence of an array, that is equal to an integer from the input. The array is also read from the console. When i run the program only the first of these members does come up, but with him also a seemingly random number of zeros, while the rest of the subsequence is omitted. If there's a better way than to use a second array, I'll be grateful if you share it. Okay, to specify- I want to know how to print all the members of the aforementioned subsequence, can you please give me a useful advice or sample? Here's the input, output and code:
4 4 56 57 58
8
4 0 0 0 0
instead of 4 4
int v = int.Parse(Console.ReadLine());
int[] valueHolder = new int[arr1.Length];
int currentSum = 0;
for (int endIndex = 0; endIndex <= arr1.Length -1; endIndex++)
{
currentSum = 0;
for (int currentSumIndex = endIndex; currentSumIndex >= 0; currentSumIndex--)
{
currentSum += arr1[currentSumIndex];
if (currentSum == v)
{
valueHolder[currentSumIndex] = arr1[currentSumIndex];
}
if (currentSum == v)
{
for (int i = 0; i <= valueHolder.Length - 1; i++)
{
Console.Write(valueHolder[i] + " ");
}
}
}
I think you would be best served by putting a break point on the line of the first for loop then stepping through your code. If you take a pad of paper and write each of the variables states as you go through it then it will be pretty obvious what's going on.
However, just to help you out.
In the first pass of the outer loop (endIndex = 0), the inner loop does NOT execute. currentSumIndex = endIndex which equals zero, which does not pass the currentSumIndex >= 0 test. Therefore the first 4 is skipped.
In the second pass, the number 4 is emitted because currentSum equals 4. However, the values of 0 are also emitted because you are walking the entire valueHolder array and spitting all of the empty values out.
From the third pass forward, currentSum will never equal the number you typed in:
The first pass of the inner loop sets currentSum to 56, which does not equal v. The second pass of the inner loops sets it to 56+4 ( currentSum += arr1[currentSumIndex] ) which is 60. Therefore, nothing will ever be emitted again as currentSum will always be the sum of all numbers from the current array position going backward to the beginning array position and therefore will always be greater than v
You don't need a second array. You just need to pay attention to what your code is doing. Side note: I have absolutely no idea why you have that inner loop or even what the 8 is supposed to represent in your example entry above.
If I was writing this, I'd change it to (assuming you can't use LINQ):
int v = int.Parse(Console.ReadLine());
for (int i= 0; i <= arr1.Length -1; i++)
{
if (arr1[i] == v) {
Console.Write(arr1[i].ToString() + " ");
}
}
Console.WriteLine();
I'm writing a physical memory manager that gets some intervals of memory from the BIOS that are not used by crucial system data. Each interval has 0 <= start <= 2^32 - 1 and 0 <= length <= 2^32. I have already filtered out the zero-length intervals.
Given two intervals S and T, I want to detect how they intersect. For example, does S start before T and end within T (picture a)? Or does S start before T and end after T (picture c)?
You'd think the solution is trivial:
uint s_end = s_start + s_length;
uint t_end = t_start + t_length;
if (s_start < t_start)
// S starts before T
else if (s_start < t_end)
// S starts within T
else
// S starts after T
if (s_end <= t_start)
// S ends before T
else if (s_end <= t_end)
// S ends within T
else
// S ends after T
The problem is overflow: I am technically limited to a 32-bit integer and the intervals can (and often do) use the whole range of available integers. For example in figure b, t_end equals 0 due to overflow. Or even, as in figure f t_start = t_end = s_start = 0 while t_length != 0.
How can I make these interval intersection conditions work with overflow taken into account?
The overflow screws up my conditions, but I really can't use a 64-bit integer for this (that would be easiest). I know it must be possible using some clever reshuffling of my conditions and using addition and subtraction, but after making endless diagrams and thinking about it for hours, I can't seem to be able to wrap my head around it.
While my problem is with 32-bit integers, in this image I used 4-bit integers just to simplify it. The problem remains the same.
OK, the issue is, if you want your ranges to span all of n-bits, any calculations based on start/end has the potential to overflow.
So the trick is to do a linear transform to a place where your start/end calculations do not overflow, do your calcs, and then linear transform back.
NOTES
Below the we can safely call end() now line, you can call the ordering checks (your original code) and it will be safe since the ordering is preserved during a linear transform.
Also, as I noted in the previous post, there is a special boundary case where even if you do this transform, you will overflow (where you span the entire line) - but you can code for that special boundary condition.
OUTPUT
5 11
CODE
#include <iostream>
using type = uint8_t;
struct segment
{
type start, length;
type end() const { return start + length; }
};
static segment
intersect( segment s, segment t )
{
type shift = std::min( s.start, t.start );
// transform so we can safely call end()
s.start -= shift; // doesn't affect length
t.start -= shift; // doesn't affect length
// we can safely call end() now ----------------------------------------------
type u_start = std::max( s.start, t.start );
type u_end = std::min( s.end(), t.end() );
type u_length = u_end - u_start;
segment u{ u_start, u_length };
// transform back
u.start += shift;
return u;
}
int main()
{
segment s{ 3, 13 }, t{ 5, 11 };
segment u = intersect( s, t );
std::cerr << uint32_t( u.start ) << " " << uint32_t( u.length ) << std::endl;
return 0;
}
Your example code does not enumerate all the cases. For example the intervals could also start or end at the same point.
To solve the overflow problem you could try to add different math based on the start comparison that will not include computing the ends at all. Something like:
if (s_start < t_start)
{
// S starts before T
uint start_offset = t_start - s_start;
if (start_offset < s_length)
{
if (s_length - start_offset < t_length)
{
// ...
}
else ...
} else ...
}
One solution is to treat an end of 0 as a special case. Weaving this into the if-statements, it becomes:
uint s_end = s_start + s_length;
uint t_end = t_start + t_length;
if (s_start < t_start)
// S starts before T
else if (t_end == 0 || s_start < t_end)
// S starts within T
else
// S starts after T
if (s_end != 0 && s_end <= t_start)
// S ends before T
else if (t_end == 0 || s_end == t_end
|| (s_end != 0 && s_end <= t_end))
// S ends within T
else
// S ends after T
This looks correct.
I don't know what do you do with conditions like (f), since 32-bit t_length will be 0 there.
Assuming you've managed this case somehow when you were filtering out length=0, which can mean both 0 and 2^32, the basic idea is this:
bool s_overflows=false;
if(s_start>0)//can't have overflow with s_start==0,
{
uint32 s_max_length=_UI32_MAX-s_start+1;
if(s_length==s_max_length) s_overflow=true;
}
bool t_overflows=false;
if(t_start>0)
{
uint32 t_max_length=_UI32_MAX-t_start+1;
if(t_length==t_max_length) t_overflow=true;
}
Then you just do your calculations, but if s_overflow is true, you don't calculate s_end -- you don't need it, since you already know it's 0x100000000. The same for t_overflow. Since these are already special cases, just like start=0, they shouldn't complicate your code much.