I was playing around with my intcode computer implementation (from advent of code 2019) and found that when I implemented the switch (to select which operation to execute) it was taking the wrong value.
The following code demonstrates this.
InstructionPointer had a value of 2, opcode had the value of 6 which means that OpcodeJumpIfFalse will be used. Function Jif() is called just fine, and it returns a value, in my case it was returning 0. Jif() also modified the value of InstructionPointer, changing its value to 9. The InstructionPointer would the be increased by 0 (return value of Jif()) and I would expect its value to be 9, but its value would go back to being 2.
InstructionPointer += opcode switch
{
OpcodeAdd => Add(),
OpcodeMultiply => Mul(),
OpcodeInput => Inp(),
OpcodeOutput => Out(),
OpcodeJumpIfTrue => Jit(),
OpcodeJumpIfFalse => Jif(),
OpcodeLessThan => Let(),
OpcodeEquals => Equ(),
OpcodeAdjustRelativeBase => Arb(),
OpcodeHalt => End(),
_ => throw new ArgumentOutOfRangeException()
};
Minimal example which shows same behavior:
int j = 2;
int i = 1;
int A()
{
j = 10;
return 0;
}
j += i switch
{
1 => A(),
_ => throw new Exception()
};
Console.WriteLine(j);
I did notice that Resharper (in the minimal example) is telling me the assignment is unused in A().
My question is, why does this happen? Is the value of j "captured" before the switch? Is this expected behavior?
For now, I have changed my code to use a temporary variable, which resolves the issue, but I would still like to know what is going on here.
Remember that the compound assignment operator a += b is the same as a = a + b (except that a is evaluated only once), see ยง7.17.2 of the spec.
Here's a slightly simpler example which doesn't use a switch, and has the same effect:
int j = 2;
int A()
{
j = 10;
return 0;
}
j = j + A();
If you don't want to think in terms of local functions, you can also write this as a class:
class C
{
private int j;
public void Test()
{
j = 2;
j = j + A();
}
private int A()
{
j = 10;
return 0;
}
}
The compiler will:
Start by evaluating j + A():
Push the current value of j, which is 2, onto the stack
Call A(), which sets j to 10 and returns 0
Push the return value of A(), which is 0, onto the stack
Add together the two values on the stack: 2 + 0
Assign this value to j
If you write the assignment the other way around, as j = A() + j, then its final value is 10. If you follow the same sequence of steps as above, you'll see why.
This general approach -- changing a variable as a side-effect of an expression which also changes that variable -- is a bad idea. It leads to very hard-to-understand code.
Related
Here is my code. I get a red line under StockPrices saying that it can not implicitly convert type decimal to int. Which I understand since StockPrices Array is set as a decimal. I can't figure out how to convert it. (If you find any other issues, please call it out. I'm still learning!)
public int FindNumTimesNegativePriceChange()
{
int difference = 0;
decimal[] negativeChange = new decimal[StockPrices];
for (int i = 0; i < StockPrices.Length - 1; ++i)
{
difference = (int)(StockPrices[i + 1] - StockPrices[i]);
if (difference < 0)
{
negativeChange++;
}
}
return negativeChange;
Currently no result is returned.
If you want a new array with the same length as an existing array, use the Length property for the source array, not the array itself:
new decimal[StockPrices.Length];
But I'm not sure that is what you are looking for at all.
You want a counter, so difference only needs to be an int in this case.
The next issue is that you are explicitly casting decimal values to an int which means you will lose precision. Other data types would throw an exception in this case but decimal allows it and will truncate the values, not round them.
For stock prices, commonly the changes are less than 1, so in this business domain precision is usually important.
If it is your intention to only count whole integer losses then you should include a comment in the code, mainly because explicit casting like this is a common code mistake, comments are a great way to prevent future code reviewers from editing your logic to correct what looks like a mistake.
Depending on your source code management practises, it can be a good idea to include a reference to the documentation / task / change request that is the authority for this logic.
public int FindNumTimesNegativePriceChange()
{
int difference = 0;
int negativeChange = 0;
for (int i = 0; i < StockPrices.Length - 1; ++i)
{
// #11032: Only counting whole dollar changes
difference = (int)(StockPrices[i + 1] - StockPrices[i]);
if (difference < 0)
{
negativeChange++;
}
}
return negativeChange;
}
A final peer review item, this method processes a single input, but currently that input needs to be managed outside of the scope of this method. In this case StockPrices must be declared at the member level, but this logic is easier to isolate and test if you refactor it to pass through the source array:
public int FindNumTimesNegativePriceChange(decimal[] stockPrices)
{
decimal difference = 0;
int negativeChange = 0;
for (int i = 0; i < stockPrices.Length - 1; ++i)
{
difference = stockPrices[i + 1] - stockPrices[i];
if (difference < 0)
{
negativeChange++;
}
}
return negativeChange;
}
This version also computes the difference (delta) as a decimal
Fiddle: https://dotnetfiddle.net/XAyFnm
I'm making a piece of code that takes the fibonacci sequence below 4 000 000 and sums up the even numbers. in order to do this I made an easy piece of code that should work but the "C" variable goes over the 4 000 000 where it shouldn't (it ends on the number:"5 702 887"), as you can see here:
int amount = 4000000;
int A = 1;
int B = 2;
int C = 0;
int answer = 0;
while (C < amount)
{
C = A + B;
if (C % 2 == 0)
{
answer = answer + C;
}
A = B;
B = C;
}
You're modifying C after you check its value. The operator is working as expected.
Your while condition is being evaluated when C = 3524578, then you're incrementing it to the >5,000,000 number, using it, and checking again.
Remember that while loops will always exit when the condition is false.
You should probably adjust the order of your tests. For instance,
int amount = 4000000;
int A = 1;
int B = 2;
int C = 3; // I've changed this to give an appropriate start value
int answer = 0;
while (C < amount)
{
if (C % 2 == 0)
{
answer = answer + C;
}
A = B;
B = C;
C = A + B; // I've moved this so that answer is not in between the altering of this value and the check for it.
}
You could also implement a for loop, which will perform this action in a bit more language-native way.
int amount = 4000000;
int A = 1;
int B = 2;
int answer = 0;
for (int C = 3; C < amount; C = A + B)
{
if (C % 2 == 0)
{
answer = answer + C;
}
A = B;
B = C;
}
The difference here is that the predicate expression is evaluated every time C is set.
I'm in an analogy mood, and I don't think I really explained the actual bug here as much as I just gave the proper code to resolve the issue (teach a man to fish, as they say), so here's a real world example of a flaw in logic like this.
Let's say you're eating orange slices and you absolutely hate seeds and want nothing to do with any oranges that contain them. Regularly, you'd pick one up, check it for seeds, and eat it if it's clear. If you come across one with seeds in it, then gross, and throw away all your remaining orange slices. In pseudo-code, while (the next one doesn't have any seeds) { eat it and grab another. }. Simple enough, right?
However, the way you've written your while loop here, you'd be eating a slice, finding seeds in your mouth, then throwing them away. And as you can see, these are very different situations.
This latter one houses folds of regret because you checked the slice (the variable) after eating (using) it, rather than before. You know not to eat any more, sure, but you've already eaten a seed. You would have been much better off to check it before you ate it, since then you'd have known it was contaminated before it came anywhere near your mouth.
I suspect that you have a false belief common to beginners. The while statement does not terminate the loop immediately the moment that the condition is violated.
The correct way to think about a while loop is that
while(condition)
statement
is logically the same thing as:
continue_label:
if (!condition) goto break_label;
statement
goto continue_label;
break_label:
The condition of a while loop is executed only while entering the loop each time. If you look at your code, C is assigned after this check. Try printing C just before your C = ... assignment - you will see that it does not go beyond the limit.
The next assignment exceeds the value, but the while loop is not entered again.
When C is checked its still bellow 4000000 but then inside the iteration it gets raised above the limit(C = A + B) and in the next iteration its above that value and the loop exits.Instead try this "very dirty" implementation:
int amount = 4000000;
int A = 1;
int B = 2;
int C = 0;
int answer = 0;
for (int i = 0; i < amount; i = A + B)
{
C = A + B;
if (C % 2 == 0)
{
answer = answer + C;
}
A = B;
B = C;
}
This question already has answers here:
What is the difference between prefix and postfix operators?
(13 answers)
Closed 9 years ago.
For example, i++ can be written as i=i+1.
Similarly, how can ++i be written in the form as shown above for i++?
Is it the same way as of i++ or if not please specify the right way to write ++i in the form as shown above for i++?
You actually have it the wrong way around:
i=i+1 is closer to ++i than to i++
The reason for this is that it anyway only makes a difference with surrounding expressions, like:
j=++i gives j the same value as j=(i+=1) and j=(i=i+1)
There's a whole lot more to the story though:
1) To be on the same ground, let's look at the difference of pre-increment and post-increment:
j=i++ vs j=++i
The first one is post-increment (value is returned and "post"=afterwards incremented), the later one is pre-increment (value is "pre"=before incremented, and then returned)
So, (multi statement) equivalents would be:
j=i; i=i+1; and i=i+1; j=i; respectively
This makes the whole thing very interesting with (theoretical) expressions like j=++i++ (which are illegal in standard C though, as you may not change one variable in a single statement multiple times)
It's also interesting with regards to memory fences, as modern processors can do so called out of order execution, which means, you might code in a specific order, and it might be executed in a totally different order (though, there are certain rules to this of course). Compilers may also reorder your code, so the 2 statements actually end up being the same at the end.
-
2) Depending on your compiler, the expressions will most likely be really the same after compilation/optimization etc.
If you have a standalone expression of i++; and ++i; the compiler will most likely transform it to the intermediate 'ADD' asm command. You can try it yourself with most compilers, e.g. with gcc it's -s to get the intermediate asm output.
Also, for many years now, compilers tend to optimize the very common construct of
for (int i = 0; i < whatever; i++)
as directly translating i++ in this case would spoil an additional register (and possible lead to register spilling) and lead to unneeded instructions (we're talking about stuff here, which is so minor, that it really won't matter unless the loop runs trillion of times with a single asm instruction or the like)
-
3) Back to your original question, the whole thing is a precedence question, as the 2 statements can be expressed as (this time a bit more exact than the upper explanation):
something = i++ => temp = i; i = i + 1; something = temp
and
something = ++i => i = i + 1; something = i
( here you can also see why the first variant would theoretically lead to more register spilled and more instructions )
As you can see here, the first expression can not easily be altered in a way I think would satisfy your question, as it's not possible to express it using precedence symbols, e.g. parentheses, or, simpler to understand, a block). For the second one though, that's easy:
++i => (++i) => { i = i + 1; return i } (pseudo code)
for the first one that would be
i++ => { return i; i = i + 1 } (pseudo code again)
As you can see, this won't work.
Hope I helped you clear up your question, if anything may need clarification or I made an error, feel free to point it out.
Technically j = ++i is the same as
j = (i = i + 1);
and j = i++; is the same as
j = i;
i = i + 1;
You can avoid writing this as two lines with this trick, though ++ doesn't do this.
j = (i = i + 1) - 1;
++i and i++ both have identical results if written as a stand alone statement (as opposed to chaining it with other operations.
That result is also identical to i += 1 and to i = i + 1.
The difference only comes in if you start using the ++i and i++ inside a larger expression.
The real meaning of this pre and post increment, you 'll know only about where you are using that.?
Main difference is
pre condition will increment first before execute any statement.
Post condition will increment after the statement executed.
Here I've mention a simple example to you.
void main()
{
int i=0, value;
value=i++; // Here I've used post increment. Here value of i will be assigned first then It'll be incremented.
// After this statement, now Value will hold the value 0 and i will hold the value 1
// Now I'm going to use pre increment
value=++i; // Here i've used pre increment. So i will be incremented first then value will be assigned to value.
// After this statement, Now value will hold the value 2 and i will hold the value 2
}
This may be done using anonymous methods:
int i = 5;
int j = i++;
is equivalent to:
int i = 5;
int j = new Func<int>(() => { int temp = i; i = i + 1; return temp; })();
However, it would make more sense if it were expanded as a named method with a ref parameter (which mimics the underlying implementation of the i++ operator):
static void Main(string[] args)
{
int i = 5;
int j = PostIncrement(ref i);
}
static int PostIncrement(ref int x)
{
int temp = x;
x = x + 1;
return temp;
}
There is no 'equivalent' for i++.
In i++ the value for i is incremented after the surrounding expression has been evaluated.
In ++i and i+1 the value for i is incremented before the surrounding expression is evaluated.
++i will increment the value of 'i', and then return the incremented value.
Example:
int i=1;
System.out.print(++i);
//2
System.out.print(i);
//2
i++ will increment the value of 'i', but return the original value that 'i' held before being incremented.
int i=1;
System.out.print(i++);
//1
System.out.print(i);
//2
I have the following code that creates 10 threads which in turn write out messages to the console:
for (int i = 0; i < 10; i++)
{
{
Thread thread = new Thread((threadNumber) =>
{
for (int j = 0; j < 10; j++)
{
Thread.Sleep(200);
Console.WriteLine(string.Format("Thread: {0}, Line: {1}", threadNumber, j));
}
});
thread.Start(i);
}
}
My understanding is that ParameterizedThreadStart takes an object for which a copy of the reference is sent to the thread. If that is the case since I have not made a local copy of i within each loop all new threads would point to the same memory location meaning certain thread numbers could be 'missed out'. Having run this though (and even against a larger number of threads/sleep times) each value of i has its own thread. Can anyone explain why?
You haven't applied anything deferred or "captured" in the sense of creating an anonymous function that would wrap i.
The lambda function here does not reference i anywhere and its state is completely internalized/contained so no issues here:
(threadNumber) =>
{
for (int j = 0; j < 10; j++)
{
Thread.Sleep(200);
Console.WriteLine(string.Format("Thread: {0}, Line: {1}", threadNumber, j));
}
});
The Start call here:
thread.Start(i);
Passes i by value (i.e. copies its value) because it is a "value type" and it's not captured in any kind of anonymous function. In this sense, it is passed as any normal struct would to any normal method (because this is exactly what is happening).
If instead you had written your lambda as this using i instead of your threadNumber:
{
for (int j = 0; j < 10; j++)
{
Thread.Sleep(200);
Console.WriteLine(string.Format("Thread: {0}, Line: {1}", i, j));
}
});
Then you would be in trouble. In this case i is referring to the original variable location and will be evaluated whenever the thread executes. This means it could be the current value of i when it was created (unlikely just due to processing times), or the value set later on in the for loop, or the last possible value 10, and quite possibly have the number skip or shared between iterations.
main()
{
....
i = index;
while (i < j)
{
if (ip[i] == "/")
{
ip[i - 1] = (double.Parse(ip[i - 1]) / double.Parse(ip[i + 1])).ToString();
for (int k = i; k < (ip.Length - 2); k++)
{
ip[k] = ip[k + 2];
}
Array.Resize(ref ip, ip.Length - 2);
j = j - 2;
i--;
}
i++;
}
}
For the above code I wanted to apply Oop's concepts.
This pattern repeats almost 5 times (for div,mul,add,sub,pow) in main program, with four identical lines .
To decrease the no of lines and there by to increase efficiency of code, I wrote the same like this.
i = index;
while (i < j)
{
if (ip[i] == "/")
{
ip[i - 1] = (double.Parse(ip[i - 1]) / double.Parse(ip[i + 1])).ToString();
ext.Resize(ip, i, j);
}
i++;
}
class ext
{
public static void Resize(string [] ip, int i, int j)
{
for (int k = i; k < (ip.Length - 2); k++) { ip[k] = ip[k + 2]; }
Array.Resize(ref ip, ip.Length - 2);
j=j-2; i--;
return ;
}
}
Code got compiled successfully. But the problem is the changes in array and variables that took place in called function are not reflecting in main program. The array and variables are remaining unchanged in main program.
I am unable to understand where I went wrong.
Plz guide me.
Thank You.
I don't think you understand what ref parameters are for - once you understand those (and the fact that arrays themselves can't change in size), you'll see why Array.Resize takes a ref parameter. Have a look at my parameter passing article for details.
You can fix your code by changing it like this:
public static void Resize(ref string [] ip, ref int i)
{
for (int k = i; k < (ip.Length - 2); k++)
{
ip[k] = ip[k + 2];
}
Array.Resize(ref ip, ip.Length - 2);
j = j - 2;
i--;
}
and calling it like this:
ext.Resize(ref ip, ref i);
However, I suspect that using a more appropriate data structure would make your code clearer. Is there any reason you can't use a List<string> instead?
You're removing items from the middle of a sequence, so shrinking its length. So using arrays is just making it difficult.
If ip was a List<string> instead of string[]:
i = index;
while (i < j)
{
if (ip[i] == "/")
{
ip[i - 1] = (double.Parse(ip[i - 1]) / double.Parse(ip[i + 1])).ToString();
ip.RemoveAt(i);
ip.RemoveAt(i);
j = j - 2;
i--;
}
i++;
}
It looks like you're parsing an arithmetic expression. However, you might want to allow for parentheses to control the order of evaluation, and that's going to be tricky with this structure.
Update: What your code says is: You are going to scan through a sequence of strings. Anywhere in that sequence you may find a division operator symbol: /. If so, you assume that the things on either side of it can be parsed with double.Parse. But:
( 5 + 4 ) / ( 6 - 2 )
The tokens on either side of the / in this example are ) and ( so double.Parse isn't going to work.
So I'm really just checking that you have another layer of logic outside this that deals with parentheses. For example, perhaps you are using recursive descent first, and then only running the piece of code you posted on sequences that contain no parentheses.
If you want the whole thing to be more "objecty", you could treat the problem as one of turning a sequence of tokens into a tree. Each node in the tree can be evaluated. The root node's value is the value of the whole expression. A number is a really simple node that evaluates to the number value itself. An operator has two child nodes. Parenthesis groups would just disappear from the tree - they are used to guide how you build it. If I have some time later I could develop this into a short example.
And another question: how are you splitting the whole string into tokens?