++ -- Operator precedence puzzle - c#

For the long time I thought I get it, and I was going to create some puzzles to learn some of my „students“ on the topic of operator precedence in c#.
But it came out that I still don't get it right. 
Puzzles:
What’s the output here?
int a = 0;
int x = --a + a++;
Console.WriteLine(x);
Console.WriteLine(a);
Output:
-2
0
All clear here, I expected this
Next, the problem one:
int b = 0;
int y = b-- + b++;
Console.WriteLine(y);
Console.WriteLine(b);
Output:
-1
0
Well, here I also expected y to be -2… Now I’m trying to apply operator precedence rules and order of evaluation, and not sure I explained it to myself.
Read this post again few times today, but still don’t quite get it why is the result here -1?
Can someone help with how is the second result evaluated. why and how is it different than the first one?

b-- is post-decrement. So:
b-- returns zero and subtracts 1 from b, leaving -1 in b.
b++ returns the -1 from the last step and adds 1, leaving 0 in b.
Final result of the addition: -1.

Do what the compiler does: break it down slowly and surely into equivalent programs.
int b = 0;
int y = b-- + b++;
is equivalent to
int b, y;
b = 0;
y = b-- + b++;
is equivalent to
int b, y;
b = 0;
int leftAddend = b--;
int rightAddend = b++;
y = leftAddend + rightAddend;
is equivalent to
int b, y;
b = 0;
int originalb1 = b;
int newb1 = originalb1 - 1;
b = newb1;
int leftAddend = originalb1;
int originalb2 = b;
int newb2 = originalb2 + 1;
b = newb2;
int rightAddend = newb2;
y = leftAddend + rightAddend;
And now annotate each with its value:
int b, y;
b = 0; // b is now 0
int originalb1 = b; // originalb1 is now 0
int newb1 = originalb1 - 1; // newb1 is now -1
b = newb1; // b is now -1
int leftAddend = originalb1; // leftAddend is now 0
int originalb2 = b; // originalb2 is now -1
int newb2 = originalb2 + 1; // newb2 is now 0
b = newb2; // b is now 0
int rightAddend = originalb2;// rightAddend is now -1
y = leftAddend + rightAddend;// y is now -1
This is precisely how the compiler deals with this situation; the compiler is just a bit more clever about optimizing away the temporaries. Analyzing expressions gets easy if you just break it down into simpler steps.

int b = 0;
int y = b-- + b++;
Break it down by step:
y = b--
Here, y is set to b (0), then b is decremented to -1.
+ b++
Here, y (0) is added to b (decremented to -1 in prev step) equaling -1, then b is incremented to zero. Output:
-1 0

Postfix --/++ returns the original value of the variable. So:
With your example b-- + b++:
b-- means decrement b, return the original value. So b = b - 1, b is now -1, and the value of the expression is 0.
b++ means increment b, return the original value. So b = b + 1, b is now 0, and the value of the expression is -1.
Then, 0 + -1 == -1. This is y. b is still 0.

This question has been answered, but I wanted to state the answer another way.
int b = 0;
int y = b-- + b++;
The expression b-- evaluates to 0 (the original value of b) and has the side effect (applied after evaluation) of decrementing b to -1.
The expression b++ evaluates to -1 (because of the previous side effect) and has the side effect (applied after evaluation) of incrementing b to 0.
This leaves the expression 0 + -1 which is -1.

Related

How to set mid in binary search?

I was working on this problem 278 First Bad Version on LeetCode. I have used binary search to get the element.
My way of getting middle index of an array m = (start + end)/2 was causing issue in case of large array, closer to MAX_LIMIT of int. First, I thought of int range overflow issue but I am not sure because it worked with end = MAX_LIMIT and some start < MAX_LIMIT even though its going over int range.
I would like to understand how m = start + (end - start)/2 is better than m = (start + end)/2
Code 1 works with input :
2147483647
98765432
But Code 1 fails with input:
2147483647
987654321
I think overflow issue should either happen in both cases or none of them.
1. Code which Worked with m = (start + end)/2 but fails for large array
public int FirstBadVersion(int n) {
if(n == 1){
return 1;
}
int s = 1;
int e = n;
int x = 0;
while(s != e){
x = (s+e)/2;
if(IsBadVersion(x)){
e = x;
}
else{
s = x + 1;
}
}
return s;
}
2. Code which worked with m = start + (end - start)/2
public int FirstBadVersion(int n) {
if(n == 1){
return 1;
}
int s = 1;
int e = n;
int x= 0;
while(s != e){
// x = (s+e)/2;
x = s + (e-s)/2;
if(IsBadVersion(x)){
e = x;
}
else{
s = x + 1;
}
}
return e;
}
You have integer overflow when computing
(a + b) / 2
when (a + b) > int.MaxValue the sum of (a + b) can't be represented as 32 bit integer (it requires 33 bits), and you have incorrect (often negative) result (when bit 33 is ignored) which you then divide by 2.
I suggest working with long in order to be safe from integer overflow:
public int FirstBadVersion(int n) {
// Special case: all versions starting from #1 failed
if (IsBadVersion(1))
return 1;
// let use long in order to avoid integer overflow
long correct = 1;
long failed = n;
// while we have unknown version between correct and failed
while (failed - correct > 1) {
int middle = (low + high) / 2); // it safe now : adding two long values
if (IsBadVersion(middle))
failed = middle;
else
correct = middle;
}
return (int)failed;
}
If using long is cheating and you want to stick to int, you can use the formula below, for int a, b we can put (note that we don't add big values a and b but their halves)
(a + b) / 2 == a / 2 + b / 2 + (a % 2 + b % 2) / 2
Please, note that your formula is not universal
(a + b) = a + (b - a) / 2;
it will work in the particular case of problem #278 where a and b are positive, but will fail in general casw, say when a = 1_000_000_000, b = -2_000_000_000.

Multi compound assignment operator?

Why the result of the following code is x = y = z = 1 ?
int x = 0, y= 0, z = 0;
x += y += z += 1;
Console.WriteLine("{0} {1} {2}", x, y, z);
Assignment statements actually evaluate to a value. The value that it evaluates to is equal to the right hand side of the assignment statement.
So x = 5; evaluates to 5.
Now let's dissect this:
x += y += z += 1;
First we replace the shorthand += to make things clearer (note that assignment operators are right-associative):
x += y += (z = z + 1)
x += (y = y + (z = z + 1))
x = x + (y = y + (z = z + 1))
Now, we evaluate! Keep in mind that assignments evaluate to the value of the right hand side!
x = x + (y = y + (z = z + 1))
x = x + (y = y + (z = 1))
x = x + (y = y + 1) // z is now 1
x = x + (y = 1)
x = x + 1 // y is now 1
x = 1
// x is now 1
As all your operators have the same priority, you need some order of execution. As seen on MSDN that order for the +=-operator is from right to left. In contrast 3 + 4 + 5 will first evaluate 3 + 4 and then add 5 to the result, as the +-operator is left to right evaluated.
The same happens in your example. First z += 1 will evaluate to one. This result (not z itself) is passed to the next +=-operator, so you get y += 1 which itself evaluates to one and is assigned to the operator += again.
An operator is basically nothing different than a simple method-call, as you can indicate by its signature:
public static int operator += (int c1, intc2) { ... }
So all you do is to call that "method" with the result of a previous call like this:
int.CallAssignPlus(ref x, int.CallIassgnPlus(ref y, int.CallAsignPlus(ref z, 1)));
Of course that code isn´t how it´s actually translated to IL, however it shows how it works.
So what´s important here is not actually the fact, that you have variables that are assigned to anything, but rather that even the result of an assignment is an expression which can be used in any other statement. Having said this z +=1 is just a statement that has a value. Thus not z is passed to y, but the value of that statement (which however is equal to the value of z).
Because:
z (0) is increased by 1 (thus:
0 + 1 = 1)
y (0) is increased by z, which is the result of the previous operation (z += 1 -> 1), hence y + z = 0 + 1 = 1
x (0) is increased by y, which is the result of the previous operation (y += z -> 1), hence x + y = 0 + 1 = 1
Even if the operations are chained, this doesn't mean they are evaluated all at once. They are always performed sequentially, from the right to the left, provided their operators have the same priority (and this is the case). Splitting your code into multiple lines following the evaluation order and simplifying the notations can probably provide a better insight on what's going on:
Int32 x = 0;
Int32 y = 0;
Int32 z = 0;
z = z + 1; // z = 0 + 1 = 1
y = y + z; // y = 0 + 1 = 1
x = x + y; // x = 0 + 1 = 1

"-+" operator c# MONO 2.10.12

I just found very strange thing in my code. By mistake I have put as an index something like this:
int a = 1;
int b = 1;
Dictionary<int, SomeClass> dic = new Dictionary<int, SomeClass> ();
dic[a -+ b].Field = 0;
As you can see there is "-+" opperator that really works as "-".
Anyway the code was having good time, was compiling until I found it.
It is part of code in Unity3d for game that I am working on now.
The question is: is it normal? Or this is know bug in mono 2 and was fixed. I cannot find any info about it.
There's nothing strange about this, and there isn't a -+ operator. There's a unary + operator and a binary - operator. Just add parentheses and some spacing to make it clearer:
int a = 1;
int b = 1;
int c = a -+ b;
int d = a - (+b); // Same as above
Note that you can use +- as well, with the unary - operator and the binary + operator:
int e = a +- b;
int f = a + (-b); // Same as above
And while you can't use ++ or -- like this, because those really are separate operators, you can add a space:
int g = a + + b;
int h = a + (+b); // Same as above
int i = a - - b;
int j = a - (-b); // Same as above
You can also have multiple unary operators chained together, for real craziness:
int k = a +-+-+-+ b;
int l = a + (-(+(-(+(-(+b)))))); // Same as above

Adding a value to the Array inside a while loop

I am making a program to run Fibonacci series. I have created 2 array.
1st array holds only 0, 1 (Array Name :- int[] arr)
2nd array holds other values eg: 1, 2, 3, 5..........etc ( Array Name:- int[] numbers)
I am using while loop to get the febonacci series and storing it in a 2nd array called int[] numbers.
after getting value using while loop, I am joing both the arrays using
int[] final = arr.Concat(number).ToArray();
At last, I have used foreach loop to add the febonacci series into the listbox.
The problem I have is that, I cannot able to concat both the arrays. I tried to assign number array at the top of the while loop. so that number variable will be accessible outside the while loop. But I am getting a error.
See the code below:
private void button1_Click(object sender, EventArgs e)
{
int x = 0;
int y = 1;
int z = 0;
if (!String.IsNullOrEmpty(q1input.Text))
{
int value;
if (int.TryParse(q1input.Text, out value))
{
int[] arr = {x, y };
while (z < value)
{
z = x + y;
int[] number = {z};
x = y;
y = z;
}
int[] final = arr.Concat(number).ToArray();
foreach (int num in final)
{
q2listbox.Items.Add(num);
}
}
else
{
MessageBox.Show("It is not a numeric value");
}
}
else
{
MessageBox.Show("Invalid Input");
}
}
List<int> number = new List<int>();
while (z < value)
{
z = x + y;
number.Add(z);
x = y;
y = z;
}
int[] final = arr.Concat(number).ToArray();
It might help if you separate your concerns: computing a Fibonacci sequence should be separated from your user interface code.
Part of your problem is that you're working with arrays (fixed length) in C# building something that adjustable in length. List<T> is a better data structure for your purposes. Despite its misleading name, it is an adjustable-length array rather than an actual list in the computer science sense.
Generating a Fibonacci sequence isn't as complicated as you're making it. This implementation:
public int[] FibonacciSequence( int x1 , int x2 , int upperBound )
{
if ( x1 < 0 ) throw new ArgumentException("x1 can't be negative") ;
if ( x2 < 0 ) throw new ArgumentException("x2 can't be negative") ;
if ( x1 == 0 && x2 == 0 ) throw new ArgumentException("x1 and x2 can't both be zero.") ;
List<int> values = new List<int>() ; // use List<int>, since we don't know the length in advance
values.Add(x1) ; // the first 2 elements are given
values.Add(x2) ;
// the remaining elements are computed by summing the previous two elements and shifting.
for ( int x = x1+x2 ; x > 0 && x < upperBound ; x = x1+x2 )
{
// add the new value to the list of values
values.Add(x) ;
x1 = x2 ; // x1 receives x2 (with the current x1 shifting off into oblivion
x2 = x ; // x2 receives x
}
int[] sequence = values.ToArray() ;
return sequence ;
}
There's no rule, just convention, that a Fibonacci sequence starts with [0,1] or [1,1]. You can then invoke this function with your desired seeds, thus:
int[] fibonacci = FibonacciSequence(1,1,int.MaxValue) ;
The cool thing about a Fibonacci sequence is that regardless of the seed values, the further out you go in the sequence, the ratio of any two adjacent values converges towards phi, the Golden Mean.
Even easier is to use some of LINQ's functionality-cum-magick. Using that, your Fibonnaci sequence becomes even simpler:
public IEnumerable<int> FibinacciSequence( int x1 , int x2 )
{
yield return x1 ;
yield return x2 ;
for ( int x = x1+x2 ; x > 0 && x < int.MaxValue ; x = x1+x2 )
{
yield return x ;
x1 = x2 ;
x2 = x ;
}
}
And its usage becomes something like:
int[] sequence = FibonacciSequence(1,1)
.TakeWhile( x => x < upperBound )
.ToArray()
;
You can even skip the 'ToArray() bit and simply say something like
foreach ( int value in FibonacciSequence(1,1).TakeWhile( x => x < upperBound ) )
{
q2listbox.Items.Add( value ) ;
}
which will evaluate the sequence in a lazy manner as you add each value to your list box.

How do I determine if adding 2 numbers will involve regourping / carryover or subracting 2 numbers will involve borrowing?

I need to create a function that will generate 2 random numbers between x and y (e.g. x = 1, y = 20) which when added will not involve regrouping / carryover or which when subracted will not involve borrowing.
For example,
18 + 1 = good
14 + 5 = good
18-7 = good
29 - 8 = good
15 + 6 = bad
6 + 7 = bad
21 - 3 = bad
36 - 8 = bad etc.
I want to create a simple worksheet generator that will generate sample problems using the requirements above.
I guess I could always convert the number to string, get the right most digit for each of the 2 numbers, convert them back to integer, and test if one is greater than the other. Repeat for all the digit. Only thing is, that is so damn ugly (read inefficient). I am sure that there is a better way. Anyone have any suggestions? Thanks
Generate them one digit at a time. e.g
a1 = rand(9)
a2 = rand(9 - a1)
b1 = rand(9)
b2 = rand(9 - b1)
x = b1*10 + a1
y = b2*10 + a2
From the construction you know that x+y will not involve any carry, because a1+a2 <= 9 and b1 + b2 <= 9.
You can do similar for subtraction.
If you want to restrict the overall range to be [1..20] instead of [1..99], just adjust the range for the leftmost digit:
b1 = rand(1)
b2 = rand(1 - b1)
using System;
class Sample {
static void Main() {
var rnd = new Random();
var x = 1;
var y = 20;
var a = rnd.Next(x, y);
var b = rnd.Next(x, y);
var op = '+';
Console.WriteLine("{0} {2} {1} = {3}", a, b, op , isValid(a, b, op)? "good":"bad");
op = '-';
Console.WriteLine("{0} {2} {1} = {3}", a, b, op , isValid(a, b, op)? "good":"bad");
}
static bool isValid(int x, int y, char op){
int a = x % 10;
int b = y % 10;
switch (op){
case '+':
return a + b < 10;
case '-':
return x >= y && a - b >= 0;
default:
throw new Exception(String.Format("unknown operator '{0}'", op));
}
}
}
Breaking up the numbers into digits is indeed exactly what you need to do. It does not matter whether you do that by arithmetic manipulation (division and modulus by 10) or by converting the numbers into strings, but fundamentally your question is precisely about the individual digits of the numbers.
For the subtraction x − y, no borrows are required if and only if none of the digits in y are greater than the corresponding digit in x.
For the addition x + y, there will be no carries if and only if the sum of each pair of corresponding digits is less than 10.
Here's some pseudo-C# for checking these conditions:
bool CanSubtractWithoutBorrow (uint x, uint y) {
while (y > 0) {
if ((x % 10) < (y % 10)) return False;
x /= 10; y /= 10;
}
return True;
}
bool CanAddWithoutCarry (uint x, uint y) {
while (x > 0 && y > 0) {
if ((x % 10) + (y % 10) >= 10) return False;
x /= 10; y /= 10;
}
return True;
}
You need to look at each pair digit in turn, and see if adding or subtracting them involves carries.
You can get the rightmost digit by taking the value modulo 10, x%10, and you can erase the right most digit by dividing by 10.
No string conversions are necessary.

Categories

Resources