using textchange event to add/subtract from a textbox - c#

I have 6 text boxes 2 for each type of bill that needs to be paid:
If I type a number into one of the two it updates the other with the difference:
The textboxes within the panels will always add to the same sum, if you change the value it automatically changes the value of its adjacent textbox, but the RENT textboxes are different.
I am trying to make it so the RENT textboxes take the (difference / 2) between the 3 pairs of other textboxes. so if patti pays 100$ more on the water bill than mike, mike has to pay that 100$ back on the rent which also subtracts 100$ off the rent from patti.
My current code results in this:
As you can see it doesn't update the rent textboxes properly. I have been trying to do this for a little over half a day, and I just can't see what I am doing wrong or what might be wrong with my math. Here is all of the code for my textboxes' textchanged events
private void txtMikeWater_TextChanged(object sender, EventArgs e)
{
double num;
bool parse = Double.TryParse(txtMikeWater.Text, out num);
if (txtMikeWater.Focused == true)
if (parse && num >= 0 && num <= expenses[2])
txtPattiWater.Text = (expenses[2] - num).ToString();
else
textBoxValidator(txtMikeWater, expenses[2], 0);
double difference = Math.Abs(num - Convert.ToDouble(txtPattiWater.Text)) / 2;
if (num > Convert.ToDouble(txtPattiWater.Text))
{
txtPattiRent.Text = ((expenses[0] / 2) + difference).ToString();
txtMikeRent.Text = ((expenses[0] / 2) - difference).ToString();
}
else
txtPattiRent.Text = ((expenses[0] / 2) - difference).ToString();
txtMikeRent.Text = ((expenses[0] / 2) + difference).ToString();
}
private void txtMikeElectric_TextChanged(object sender, EventArgs e)
{
double num;
bool parse = Double.TryParse(txtMikeElectric.Text, out num);
if (txtMikeElectric.Focused)
if (parse && num >= 0 && num <= expenses[3])
txtPattiElectric.Text = (expenses[3] - num).ToString();
double difference = Math.Abs(num - Convert.ToDouble(txtPattiElectric.Text)) / 2;
if (num > Convert.ToDouble(txtPattiElectric.Text))
{
txtPattiRent.Text = ((expenses[0] / 2) + difference).ToString();
txtMikeRent.Text = ((expenses[0] / 2) - difference).ToString();
}
else if (num < Convert.ToDouble(txtPattiElectric.Text))
{
txtPattiRent.Text = ((expenses[0] / 2) - difference).ToString();
txtMikeRent.Text = ((expenses[0] / 2) + difference).ToString();
}
}
private void txtMikeInternet_TextChanged(object sender, EventArgs e)
{
double num;
bool parse = Double.TryParse(txtMikeInternet.Text, out num);
if (txtMikeInternet.Focused)
if (parse && num >= 0 && num <= expenses[1])
txtPattiInternet.Text = (expenses[1] - num).ToString();
double difference = Math.Abs(num - Convert.ToDouble(txtPattiInternet.Text)) / 2;
if (num > Convert.ToDouble(txtPattiInternet.Text))
{
txtPattiRent.Text = ((expenses[0] / 2) + difference).ToString();
txtMikeRent.Text = ((expenses[0] / 2) - difference).ToString();
}
else if (num < Convert.ToDouble(txtPattiInternet.Text))
{
txtPattiRent.Text = ((expenses[0] / 2) - difference).ToString();
txtMikeRent.Text = ((expenses[0] / 2) + difference).ToString();
}
}
private void txtPattiWater_TextChanged(object sender, EventArgs e)
{
double num;
bool parse = Double.TryParse(txtPattiWater.Text, out num);
if (txtPattiWater.Focused == true)
if (parse && num >= 0 && num <= expenses[2])
txtMikeWater.Text = (expenses[2] - num).ToString();
double difference = Math.Abs(num - Convert.ToDouble(txtMikeWater.Text)) / 2;
if (num < Convert.ToDouble(txtMikeWater.Text))
{
txtPattiRent.Text = ((expenses[0] / 2) + difference).ToString();
txtMikeRent.Text = ((expenses[0] / 2) - difference).ToString();
}
else
{
txtPattiRent.Text = ((expenses[0] / 2) - difference).ToString();
txtMikeRent.Text = ((expenses[0] / 2) + difference).ToString();
}
}
private void txtPattiElectric_TextChanged(object sender, EventArgs e)
{
double num;
bool parse = Double.TryParse(txtPattiElectric.Text, out num);
if (txtPattiElectric.Focused)
if (parse && num >= 0 && num <= expenses[3])
txtMikeElectric.Text = (expenses[3] - num).ToString();
double difference = Math.Abs(num - Convert.ToDouble(txtMikeElectric.Text)) / 2;
if (num < Convert.ToDouble(txtMikeElectric.Text))
{
txtPattiRent.Text = ((expenses[0] / 2) + difference).ToString();
txtMikeRent.Text = ((expenses[0] / 2) - difference).ToString();
}
else if (num > Convert.ToDouble(txtMikeElectric.Text))
{
txtPattiRent.Text = ((expenses[0] / 2) - difference).ToString();
txtMikeRent.Text = ((expenses[0] / 2) + difference).ToString();
}
}
private void txtPattiInternet_TextChanged(object sender, EventArgs e)
{
double num;
bool parse = Double.TryParse(txtPattiInternet.Text, out num);
if (txtPattiInternet.Focused)
if (parse && num >= 0 && num <= expenses[1])
txtMikeInternet.Text = (expenses[1] - num).ToString();
double difference = Math.Abs(num - Convert.ToDouble(txtMikeWater.Text)) / 2;
if (num < Convert.ToDouble(txtMikeWater.Text))
{
txtPattiRent.Text = ((expenses[0] / 2) + difference).ToString();
txtMikeRent.Text = ((expenses[0] / 2) - difference).ToString();
}
else if (num > Convert.ToDouble(txtMikeWater.Text))
{
txtPattiRent.Text = ((expenses[0] / 2) - difference).ToString();
txtMikeRent.Text = ((expenses[0] / 2) + difference).ToString();
}
}
The expenses variable just stores the sum the pairs of the textboxes are supposed to have.
If anyone can please help I would appreciate it.
EDIT Just for some more clarity regarding the expenses variable.
expenses[0] = total rent
expenses[1] = total internet
expenses[2] = total water
expenses[3] = total electricity

Looks like your rent recalculations are only changing based on the difference of a single expense, not the total difference of all of them aggregated.
I suggest you create a single UpdateRent() method which sums up the total expenses paid for each person then calculates the difference:
private void txtPattiElectric_TextChanged(object sender, EventArgs e)
{
double num;
bool parse = Double.TryParse(txtPattiElectric.Text, out num);
if (txtPattiElectric.Focused)
if (parse && num >= 0 && num <= expenses[3])
txtMikeElectric.Text = (expenses[3] - num).ToString();
UpdateRent();
}
Your rent calculation might look like:
private void UpdateRent()
{
double pattiPaid = GetPattiWater() + GetPattiElectric() + GetPattiInternet();
double mikePaid = GetMikeWater() + GetMikeElectric() + GetMikeInternet();
double difference = pattiPaid - mikePaid;
double baseRent = GetRequiredMonthlyRent() / 2;
double pattiRent = baseRent - difference;
double mikeRent = baseRent + difference;
txtPattiRent.Text = pattiRent.ToString();
txtMikeRent.Text = mikeRent.ToString();
}
I also suggest you move most of the parsing/handling code to helper methods (indicated above) just to make it easier to track and debug the logic in general.
EDIT: Also note that the code eliminates the checking to see who paid more. It all works out in the math. For example, if Mike paid more, then difference is negative. Then that negative number is "subtracted" from Patti's base rent effectively increasing it. Feel free to re-introduce if checks to do the same work if you find it makes your code easier to understand, debug, and maintain.
EDITx2: It wasn't very clear in my original answer. Methods like GetPattiWater() and GetRequiredMonthlyRent() should simply read/return the current value:
private double GetPattiWater()
{
double amount;
Double.TryParse(txtPattiWater.Text, out amount);
return amount;
}
private double GetRequiredMonthlyRent()
{
return expenses[3];
}
You may need to do some special handling for temporary/blank/invalid non-parseable input in the text fields (the above would just return 0) but it might be simpler just to treat it as zero temporarily.

Related

Double returning NaN but not all the time

I am baffled here. I have a function to return a double, sometimes it returns the correct value, but most of the times it return NaN. From my understanding NaN is returned when we have something like 0/0. Below is the function returning NaN, all it's variables are declared as doubles.
public double SuperiorValue(List<double> l)
{
valueKn[0] = 0;
valueKn[1] = 0;
valueKn[2] = 1.69;
valueKn[3] = 1.18;
valueKn[4] = 0.95;
valueKn[5] = 0.82;
valueKn[6] = 0.75;
valerKn[7] = 0.67;
valueKn[8] = 0.63;
valueKn[9] = 0.58;
valueKn[10] = 0.561;
valueKn[11] = 0.542;
valueKn[12] = 0.523;
valueKn[13] = 0.504;
valueKn[14] = 0.485;
valueKn[15] = 0.466;
valueKn[16] = 0.447;
valueKn[17] = 0.428;
valueKn[18] = 0.409;
valueKn[19] = 0.39;
valueKn[20] = 0.382;
Xm = (l.Sum()) / (l.Count);
for (int i = 0; i < l.Count; i++)
{
sumTemporary = l[i] - Xm;
sum = sum + sumTemporary;
}
kn = valueKn[l.Count];
sx = Math.Sqrt((1 / l.Count - 1) * (sum * sum));
Vx = sx / Xm;
Xksup = Xm * (1 + kn * Vx);
Xkinf = Xm * (1 - kn * Vx);
return Xksup;
}
What baffles me even more is that never is the list made of less than 3 elements and greater than 15, and it still often returns NaN but like I said sometimes it returns the correct value. Any thoughts on this ?
Look at
Math.Sqrt((1 / l.Count - 1) * (sum * sum))
The 1 / l.Count is an integer division, it will be 0 for all l.Count > 1 and then you are computing Sqrt(-1 * (sum * sum)) .
But (1.0 / l.Count - 1) would still be negative, you probably want (1.0 / (l.Count - 1))
The fix is then:
Math.Sqrt((1.0 / (l.Count - 1)) * (sum * sum))

Pagination Math Issue

I have a pagination issue :
I have a large number of pages as results in my table ~50.000 pages and my pagination logic is something like :
1 2 3 ...50000
I would like to do something like :
1 2 3 10 100 500 1000 5000 10000 50000
And when i click for example 1111 :
1 1109 1110 1111 1112 1113 1114 1120 1200 1700 2200 3000 8000 10000 50000
so far I;ve tried something like this :
int Max_count = (int)Math.Floor(Math.Log10(totalPages) + 1);
for (int index = start; index <= end; index++)
{
if (index == pageNumber)
{
header.Items.Add(new PagingHeaderModelItem(PageHeaderItemType.CurrentPage, pageNumber));
}
else if (index == start)
{
header.Items.Add(new PagingHeaderModelItem(PageHeaderItemType.StartPage, 0));
}
else if (index == end)
{
header.Items.Add(new PagingHeaderModelItem(PageHeaderItemType.EndPage, totalPages - 1));
}
else if ((index == start + 1) && (index > 1))
{
header.Items.Add(new PagingHeaderModelItem(PageHeaderItemType.MorePages, -1));
}
else if ((index == end - 1) && (index < totalPages - 2))
{
header.Items.Add(new PagingHeaderModelItem(PageHeaderItemType.MorePages, -1));
}
else if ((index > 100) && (index > totalPages / 2))
{
header.Items.Add(new PagingHeaderModelItem(PageHeaderItemType.SimplePage, index));
}
else if ((pageNumber + 2 > index) && index + 10 < totalPages && !isSecond)
{
for (int temp = 1; temp < Max_count; temp++)
{
int power_var = (int)Math.Pow(10, temp);
int power_var_prev = (int)Math.Pow(10, temp - 1);
if ((pageNumber > power_var) || pageNumber < 10)
{
header.Items.Add(new PagingHeaderModelItem(PageHeaderItemType.SimplePage, power_var - 1));
header.Items.Add(new PagingHeaderModelItem(PageHeaderItemType.SimplePage, power_var - 1 + power_var_prev));
temp++;
}
}
isSecond = true;
}
else if (index - start < 3)
{
header.Items.Add(new PagingHeaderModelItem(PageHeaderItemType.SimplePage, index));
}
But i Feel like I'm not close to this at all. I'm not asking for a solution more of a hint or a formula I could use to do this by myself
LATER EDIT
The pattern should be like :
n-3, // 1 //1
n-2, // 2 //1109
n-1, // 3 //1110
**n**, // **4** //1111
n+1, //5 //1112
n+2, //6 //1113
n+3, //7 //1114
Math.Floor((index + 10)) / 10) * 10, //10 //1120
Math.Floor((index + 10)) / 10) * 10 +50, //60 //1170
Math.Floor((index + 100)) / 100) * 100, //100 //1200
Math.Floor((index + 100)) / 100) * 100+500,//600 //1700
Math.Floor((index + 1000)) / 1000) * 1000,//1000 //2000
Math.Floor((index + 1000)) / 1000) * 1000+5000,//6000/7000
....
Here's some code to print the desired values:
(it does print 1108 as well, but that should be easy enough to work around)
(changed +50, +500, etc. to +40, +400, etc. because I prefer that)
int min = 1, max = 50000;
if (val-3 > min)
Console.WriteLine(min);
for (int i = Math.Max(min, val-3); i <= Math.Min(max, val+3); i++)
Console.WriteLine(i);
int last = -1;
for (int i = 10; ; i *= 10)
{
int next = (val+3 + i) / i * i;
if (next > max)
break;
// prevent printing something like 90, 130, 100, 500 (100 won't print)
if (next > last)
Console.WriteLine(next);
next += 4*i;
if (next > max)
break;
Console.WriteLine(next);
last = next;
}
Live demo.
If you want to print it from the value to the minimum as well, it could be a simple case of copying the for-loop and inverting the values: (it will print the values from the largest, changing this will require a stack data structure)
for (int i = 10; ; i *= 10)
{
int next = (val-3 - i) / i * i;
if (next < min)
break;
if (next < last)
Console.WriteLine(next);
next -= 4*i;
if (next < min)
break;
Console.WriteLine(next);
last = next;
}
if (last != min)
Console.WriteLine(min);
Here's another idea:
Taking 1111 in 1..50000 as an example.
Take the 2 values before and the 2 values after - 1109, 1110, 1111, 1112, 1113.
Let's say we want an exponential growth towards the target, with 5 points in between.
The range of values upwards would be 50000 - 1113 = 48887 (starting from biggest value above).
Then we want to find x such that (5x)^2 = 48887. This is fairly easy to calculate, just square root 48887 and divide by 5 - sqrt(48887) / 5 = 44.22
Then the values would be:
1113 + (1 * 44.22) ^ 2 = 3068
1113 + (2 * 44.22) ^ 2 = 8934
1113 + (3 * 44.22) ^ 2 = 18712
1113 + (4 * 44.22) ^ 2 = 32400
1113 + (5 * 44.22) ^ 2 = 50000
Similarly for downwards.
You can probably base the number of values in between on how far the target is, if you wish.
If you'd prefer more round numbers, I'd have to think about that a bit more.

Argument out of range exception thrown

I saw this function on Percentile calculation, so I copied it and pasted it into the compiler, and it gives me an OutOfRange exception at
else
{
int k = (int)n;
double d = n - k;
return sequence[k - 1] + d * (sequence[k] - sequence[k - 1]);//EXCEPTION
}
What could be the source of the problem, and how do I solve it?
Function:
public double Percentile(double[] sequence, double excelPercentile)
{
Array.Sort(sequence);
int N = sequence.Length;
double n = (N - 1) * excelPercentile + 1;
// Another method: double n = (N + 1) * excelPercentile;
if (n == 1d) return sequence[0];
else if (n == N) return sequence[N - 1];
else
{
int k = (int)n;
double d = n - k;
return sequence[k - 1] + d * (sequence[k] - sequence[k - 1]);
}
}
The issue is that k is a number larger than the number of items in the array.
As was mentioned, the function is designed to work with values between 0 and 1. Restricting the input should correct the problem.
public double Percentile(double[] sequence, double excelPercentile)
{
//if(excelPercentile > 1)
//excelPercentile = 1;
//else if(excelPercentile < 0)
//excelPercentile = 0;
//Depending on how you validate the input you can assume that it's a whole number percentage. Then you only need to check for the number to be between 0 and 100
if(excelPercentile > 100)
excelPercentile = 100;
else if(excelPercentile < 0)
excelPercentile = 0;
excelPercentile /= 100;
Array.Sort(sequence);
int N = sequence.Length;
double n = (N - 1) * excelPercentile + 1;
// Another method: double n = (N + 1) * excelPercentile;
if (n == 1d) return sequence[0];
else if (n == N) return sequence[N - 1];
else
{
int k = (int)n;
double d = n - k;
return sequence[k - 1] + d * (sequence[k] - sequence[k - 1]);
}
}

Performance related issue regarding times like 00:00:00:000

I have this ListView. My goal is to add / subtract a fixed time to all the times / selected times in the list. The thing is that there will be somewhat around 1000-3000 rows in it, so it takes some time. My goal is to make this as fast for the computer as possible.
Right now if I spam-run the function, it takes some time for the form to finish, and if I chose to do it with selected rows, half of them, then the form freezes for a while before finishing.
My code right now looks like this (here's a picture of the code for better view):
public void PlusMinus(bool plus)
{
int items_to_set = 0;
int msec_start = 0;
int msec_end = 0;
int msec_box = Convert.ToInt32(mskTime.Text.Substring(9, 3)) +
(Convert.ToInt32(mskTime.Text.Substring(6, 2)) * 1000) +
(Convert.ToInt32(mskTime.Text.Substring(3, 2)) * 60000) +
(Convert.ToInt32(mskTime.Text.Substring(0, 2)) * 3600000);
if (rbtnAll.Checked) { items_to_set = listSub.Items.Count; }
else { items_to_set = listSub.SelectedItems.Count; }
if (rbtnAll.Checked)
{
for (int i = 0; i < items_to_set; i++)
{
msec_start = Convert.ToInt32(listSub.Items[i].SubItems[1].Text.Substring(9, 3)) +
(Convert.ToInt32(listSub.Items[i].SubItems[1].Text.Substring(6, 2)) * 1000) +
(Convert.ToInt32(listSub.Items[i].SubItems[1].Text.Substring(3, 2)) * 60000) +
(Convert.ToInt32(listSub.Items[i].SubItems[1].Text.Substring(0, 2)) * 3600000);
msec_end = Convert.ToInt32(listSub.Items[i].SubItems[2].Text.Substring(9, 3)) +
(Convert.ToInt32(listSub.Items[i].SubItems[2].Text.Substring(6, 2)) * 1000) +
(Convert.ToInt32(listSub.Items[i].SubItems[2].Text.Substring(3, 2)) * 60000) +
(Convert.ToInt32(listSub.Items[i].SubItems[2].Text.Substring(0, 2)) * 3600000);
if (plus == true) { msec_start += msec_box; msec_end += msec_box; }
else { msec_start -= msec_box; msec_end -= msec_box; }
TimeSpan ts = TimeSpan.FromMilliseconds(msec_start);
listSub.Items[i].SubItems[1].Text = string.Format("{0:D2}:{1:D2}:{2:D2}:{3:D3}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds);
ts = TimeSpan.FromMilliseconds(msec_end);
listSub.Items[i].SubItems[2].Text = string.Format("{0:D2}:{1:D2}:{2:D2}:{3:D3}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds);
}
}
else
{
for (int i = 0; i < items_to_set; i++)
{
msec_start = Convert.ToInt32(listSub.Items[listSub.SelectedIndices[i]].SubItems[1].Text.Substring(9, 3)) +
(Convert.ToInt32(listSub.Items[listSub.SelectedIndices[i]].SubItems[1].Text.Substring(6, 2)) * 1000) +
(Convert.ToInt32(listSub.Items[listSub.SelectedIndices[i]].SubItems[1].Text.Substring(3, 2)) * 60000) +
(Convert.ToInt32(listSub.Items[listSub.SelectedIndices[i]].SubItems[1].Text.Substring(0, 2)) * 3600000);
msec_end = Convert.ToInt32(listSub.Items[listSub.SelectedIndices[i]].SubItems[2].Text.Substring(9, 3)) +
(Convert.ToInt32(listSub.Items[listSub.SelectedIndices[i]].SubItems[2].Text.Substring(6, 2)) * 1000) +
(Convert.ToInt32(listSub.Items[listSub.SelectedIndices[i]].SubItems[2].Text.Substring(3, 2)) * 60000) +
(Convert.ToInt32(listSub.Items[listSub.SelectedIndices[i]].SubItems[2].Text.Substring(0, 2)) * 3600000);
if (plus == true) { msec_start += msec_box; msec_end += msec_box; }
else { msec_start -= msec_box; msec_end -= msec_box; }
TimeSpan ts = TimeSpan.FromMilliseconds(msec_start);
listSub.Items[listSub.SelectedIndices[i]].SubItems[1].Text = string.Format("{0:D2}:{1:D2}:{2:D2}:{3:D3}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds);
ts = TimeSpan.FromMilliseconds(msec_end);
listSub.Items[listSub.SelectedIndices[i]].SubItems[2].Text = string.Format("{0:D2}:{1:D2}:{2:D2}:{3:D3}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds);
}
}
}
So is there some changes I could make that would be a somewhat big positive impact on the performance here?
Don't parse the strings at all. Instead, store the data as TimeSpans so there is no parsing at all.
Storing data as strings is bad-practice anyway because it clutters up your code with serialization and deserialization.
Where you store the data is not that important. You can use the object Tag property that is on most WinForms objects or store it elsewhere (maybe in a custom list or dictionary).
Also, your code looks highly redundant. Put common subexpressions into local variables. This will improve code quality and performance.

C# which is faster do/while or for?

I have a C# .NET 2.0 script and I want to know why the following code would be faster than a do while loop of the same kind.
private double getStop(double avgPrice, bool longTrading)
{
double stopS = 0.0;
double stopL = 0.0;
for (int i = 0; i < 13; i++)
{
if (i == 0 || i == 12)
{
stopS = 0.0;
stopL = 0.0;
}
else
{
if ((lines[i] - ((lines[i] - lines[i - 1]) / 2)) < avgPrice && avgPrice < (lines[i + 1] - ((lines[i + 1] - lines[i]) / 2)))
{
if (avgPrice < lines[i])
{
stopL = (lines[i] - ((lines[i] - lines[i - 1]) / 2));
stopS = lines[i];
} else {
stopL = lines[i];
stopS = (lines[i + 1] - ((lines[i + 1] - lines[i]) / 2));
}
}
}
}
if (longTrading)
{
return stopL;
} else {
return stopS;
}
}
Also, would it be faster just to explicitly state each if statement instead of doing them inside of a for loop?
Being that this was answered so fast, why would this run far slower than the above code?
private double getStop(double avgPrice, bool longTrading)
{
double stopS = 0.0;
double stopL = 0.0;
for (int i = 0; i < 13; i++)
{
if (i == 0 || i == 12)
{
stopS = 0.0;
stopL = 0.0;
skip = true;
}
if (!skip && (lines[i] - ((lines[i] - lines[i - 1]) / 2)) < avgPrice && avgPrice < (lines[i + 1] - ((lines[i + 1] - lines[i]) / 2)))
{
if (avgPrice < lines[i])
{
stopL = (lines[i] - ((lines[i] - lines[i - 1]) / 2));
stopS = lines[i];
} else {
stopL = lines[i];
stopS = (lines[i + 1] - ((lines[i + 1] - lines[i]) / 2));
}
}
}
skip = false;
}
if (longTrading)
{
return stopL;
} else {
return stopS;
}
}
The performance difference should be negligible, but the for loop is clearer so I would go with that.
They should be essentially equivalent. Your 'for' loop gets evaluated as:
int i = 0;
while (i < 13)
{
//all other stuff
i++;
};
loop variations aren't too much different, it depends on the context and the programming language.
But my opinion is, for statement don't do until the constaint(s) is/are matched, therefore it should be faster than do/while.

Categories