C# Strange issue with checking progress - c#

I have a loop inside a constructor, that creates and initialises a jagged array of objects. Inside the loop I have it print to the console on each iteration, so that I know how far through the process it is. It only prints to the console on a multiple of 5 (although it's only printing on a multiple of 10 for some reason) so that it doesn't spam the screen. Eg, 15% 20% 25%.
When I run the code on .Net 2.0 on Windows, it prints every 10% (rather than 5%). If I run the same code on Mono on an ARM machine it doesn't print any progress out at all.
What is causing Mono to not give any output?
Why is it printing only in increments of 10% rather than 5%?
Thanks
Here's the code:
public Map(int NumberOfRows, int NumberOfColumns)
{
Rows = NumberOfRows;
Columns = NumberOfColumns;
TileGrid = new Tile[NumberOfRows][];
for (int x = 0; x < TileGrid.Length; x++)
{
TileGrid[x] = new Tile[NumberOfColumns];
for (int y = 0; y < TileGrid[x].Length; y++)
{
TileGrid[x][y] = new Tile();
}
if (((double)x / Rows) * 100 % 5 == 0)
{
Console.WriteLine("{0}%", ((double)x / Rows) * 100);
}
}
}

The problem is basically that you're performing an equality check on a floating point number, which is pretty much never a good idea.
This is better... but still not good:
int percentage = (x * 100) / Rows;
if (percentage % 5 == 0)
{
Console.WriteLine("{0}%", percentage);
}
That's still not going to print the percentage unless you end up exactly at multiples of 5%. So if there are 12 items, it's not going to work. Try this instead:
// Before the loop
int lastPrintedPercentage = -5; // So that we always print on the first loop
// Within the loop
int percentage = (x * 100) / Rows;
if (percentage >= lastPrintedPercentage + 5)
{
Console.WriteLine("{0}%", percentage);
lastPrintedPercentage = percentage;
}

floating point operations must be compared against the machine epsilon because of the floating point rounding errors
http://en.wikipedia.org/wiki/Machine_epsilon
This expression can be never null according to the floating point rounding error
if (((double)x / Rows) * 100 % 5 == 0)
must be
if (Math.Abs(((double)x / Rows) * 100 % 5) < MACHINE_EPSILON)
But there is no definition in the .NET Framework for the machine epsilon. So don't use floating point operations for this at all or use a delta technique like
var step = (double)x / Rows) * 5;
var current = step ;
...
if((double)x / Rows) >= current)
{
current += step;
// Your code here
}
...

Related

C# WinsForm, Frequency Distribution Table [Updated]

Update 01
Thanks to Caius, found the main problem, the logic on the "if" was wrong, now fixed and giving the correct results. The loop still create more positions than needed on the secondary List, an extra position for each number on the main List.
I've updated the code bellow for refence for the following question:
-001 I can figure out why it create positions that needed, the for loop should run only after the foreach finishes its loops correct?
-002 To kind of solving this issue, I've used a List.Remove() to remove all the 0's, so far no crashes, but, the fact that I'm creating the extra indexes, and than removing them, does means a big performance down if I have large list of numbers? Or is an acceptable solution?
Description
It supposed to read all numbers in a central List1 (numberList), and count how many numbers are inside a certain (0|-15 / 15|-20) range, for that I use another List, that each range is a position on the List2 (numberSubList), where each number on List2, tells how many numbers exists inside that range.
-The range changes as the numbers grows or decrease
Code:
void Frequency()
{
int minNumb = numberList.Min();
int maxNumb = numberList.Max();
int size = numberList.Count();
numberSubList.Clear();
dGrdVFrequency.Rows.Clear();
dGrdVFrequency.Refresh();
double k = (1 + 3.3 * Math.Log10(size));
double h = (maxNumb - minNumb) / k;
lblH.Text = $"H: {Math.Round(h, 2)} / Rounded = {Math.Round(h / 5) * 5}";
lblK.Text = $"K: {Math.Round(k, 4)}";
if (h <= 5) { h = 5; }
else { h = Math.Round(h / 5) * 5; }
int counter = 1;
for (int i = 0; i < size; i++)
{
numberSubList.Add(0); // 001 HERE, creating more positions than needed, each per number.
foreach (int number in numberList)
{
if (number >= (h * i) + minNumb && number < (h * (i + 1)) + minNumb)
{
numberSubList[i] = counter++;
}
}
numberSubList.Remove(0); // 002-This to remove all the extra 0's that are created.
counter = 1;
}
txtBoxSubNum.Clear();
foreach (int number in numberSubList)
{
txtBoxSubNum.AppendText($"{number.ToString()} , ");
}
lblSubTotalIndex.Text = $"Total in List: {numberSubList.Count()}";
lblSubSumIndex.Text = $"Sum of List: {numberSubList.Sum()}";
int inc = 0;
int sum = 0;
foreach (int number in numberSubList)
{
sum = sum + number;
int n = dGrdVFrequency.Rows.Add();
dGrdVFrequency.Rows[n].Cells[0].Value = $"{(h * inc) + minNumb} |- {(h * (1 + inc)) + minNumb}";
dGrdVFrequency.Rows[n].Cells[1].Value = $"{number}";
dGrdVFrequency.Rows[n].Cells[2].Value = $"{sum}";
dGrdVFrequency.Rows[n].Cells[3].Value = $"{(number * 100) / size} %";
dGrdVFrequency.Rows[n].Cells[4].Value = $"{(sum * 100) / size} %";
inc++;
}
}
Screen shot showing the updated version.
I think, if your aim is to only store eg 17 in the "15 to 25" slot, this is wonky:
if (number <= (h * i) + minNumb) // Check if number is smaller than the range limit
Because it's found inside a loop that will move on to the next range, "25 to 35" and it only asks if the number 17 is less than the upper limit (and 17 is less than 35) so 17 is accorded to the 25-35 range too
FWIW the range a number should be in can be derived from the number, with (number - min) / number_of_ranges - at the moment you create your eg 10 ranges and then you visit each number 10 times looking to put it in a range, so you do 9 times more operations than you really need to

How to iterate properly from 0.0 to 1.0 in a 'for' loop?

This is a fairly simple question, yet I am struggling to find an elegant solution for!
Suppose you want to iterate from 0.0 to 1.0 in discrete steps, you'll use a for loop that uses int since it's discouraged to use float due to precision errors.
The simplest approach is the following but it's flawed as it never outputs 1.0:
private void sample1(int steps = 100)
{
var floats = new float[steps]; // 100 values
for (var i = 0; i < steps; i++) // goes from 0 to 99
{
var f = 1.0f / steps * i; // will only go from 0.0 to 0.99, never reaches 1.0
floats[i] = f;
}
}
A first attempt to address the issue, it works but we end with one more value:
private void sample2(int steps = 100)
{
var n = steps + 1;
var floats = new float[n]; // 101 values now!
for (var i = 0; i < n; i++) // goes from 0 to 100
{
var f = 1.0f / n * i; // goes from 0.0 to 1.0 but now we have an extra value
floats[i] = f;
}
}
A second attempt to address the issue, we don't have an extra value but last is never really 1.0:
private void sample3(int steps = 100)
{
var floats = new float[steps]; // 100 values
for (var i = 0; i < steps; i++) // goes from 0 to 99
{
var f = 1.0f / steps * i * ((steps - 1.0f) / steps); // goes from 0.0 to 0.999...
floats[i] = f;
}
}
Question:
How does one properly loop from 0.0 to 1.0 as discrete steps in a for loop that uses int?
(pseudo-code is just fine)
Count out loud to 10. If you included zero in your counting, you actually spoke out eleven numbers, not 10. Since you want to include zero without making any progress towards your goal of 1.0f, the other steps-1 slices of 1.0f must sum up to 1.0.
Or to think about it from another angle:
To get 1 your numerator and denominator need to be equal. Since your for-loop runs from 0 to steps exclusive, or steps-1 inclusive, your denominator must be steps-1.

When arrays go awry?

I'm trying to learn C# by solving mathematical problems. For example, I'm working on finding the sum of factors of 3 or 5 in the first 1000 positive numbers. I have the basic shell of the code laid out, but it isn't behaving how I'm expecting it to.
Right now, instead of getting a single output of 23, I am instead getting 1,1,3,3,5,5,7,7,9,9. I imagine I messed up the truncate function somehow. Its a bloody mess, but its the only way I can think of checking for factors. Second, I think that the output is writing during the loop, instead of patiently waiting for the for() loop to finish.
using System;
namespace Problem1
{
class Problem1
{
public static void Main()
{
//create a 1000 number array
int[] numberPool = new int[10];
//use for loop to assign the first 1000 positive numbers to the array
for (int i = 0; i < numberPool.Length; i++)
{
numberPool[i] = i + 1;
}
//check for factors of 3 or 5 using if/then statment
foreach (int i in numberPool)
if ((i / 3) == Math.Truncate((((decimal)(i / 3)))) || ((i / 5) == Math.Truncate(((decimal)(i / 5)))))
{
numberPool[i] = i;
}
else
{
numberPool[i] = 0;
}
//throw the 0s and factors together and get the sum!
int sum = 0;
for (int x = 0;x < numberPool.Length;x++)
{
sum = sum + numberPool[x];
}
Console.WriteLine(sum);
Console.ReadLine();
//uncomment above if running in vbs
}
}
}
The foreach loop has a few errors.
If you want to modify the array you are looping through use a for loop. Also, use modulus when checking remainders.
for (int i = 0; i < numberPool.Length; i++)
{
if (numberPool[i] % 3 == 0 || numberPool[i] % 5 == 0)
{
// Do nothing
}
else
{
numberPool[i] = 0;
}
}
Modulus (%) will give the remainder when dividing two integers.
Another useful shortcut, variable = variable + x can be replaced with variable += x
Please note that there are more concise ways of doing this but since you are learning the language I will leave that for you to find.
#kailanjian gave some great advice for you but here is another way your initial logic can be simplified for understanding:
//the sum of factors
int sum = 0;
//the maximum number we will test for
int maxNum = 1000;
//iterate from 1 to our max number
for (int i = 1; i <= maxNum; i++)
{
//the number is a factor of 3 or 5
if (i % 3 == 0 || i % 5 == 0)
{
sum += i;
}
}
//output our sum
Console.WriteLine(sum);
You also stated:
Second, I think that the output is writing during the loop, instead of patiently waiting for the for() loop to finish.
Your program logic will execute in the order that you list it and won't move on to the next given command until it is complete with the last. So your sum output will only be printed once it has completed our for loop iteration.

How to limit the number of cycles of a loop under some condition?

I make a loop like this :
int total;
total = ((toVal - fromVal) + 1) * 2;
RadProgressContext progress = RadProgressContext.Current;
progress.Speed = "N/A";
finYear = fromVal;
for (int i = 0; i < total; i++)
{
decimal ratio = (i * 100 / total);
progress.PrimaryTotal = total;
progress.PrimaryValue = total;
progress.PrimaryPercent = 100;
progress.SecondaryTotal = 100; // total;
progress.SecondaryValue = ratio;//i ;
progress.SecondaryPercent = ratio; //i;
progress.CurrentOperationText = "Step " + i.ToString();
if (!Response.IsClientConnected)
{
//Cancel button was clicked or the browser was closed, so stop processing
break;
}
progress.TimeEstimated = (total - i) * 100;
//Stall the current thread for 0.1 seconds
System.Threading.Thread.Sleep(100);
}
Now i want a specific method to run according to toVal & fromVal
in the previous loop but not with the same number of cycles
i want to to run it in a loop like this :
for (fromVal; fromVal < toVal ; fromVal++)
{
PrepareNewEmployees(calcYear, fromVal);
}
for example :
fromVal = 2014
toVal = 2015
so i want to run twice not 4 times! like this :
PrepareNewEmployees(calcYear, 2014);
PrepareNewEmployees(calcYear, 2015);
but in the previous loop for (int i = 0; i < total; i++)
You're missing the point of progress bar updating. You're not supposed to run 4 iterations and do some work every 2 iterations, but the oposite. Do a loop like:
for (int i = fromVal; i < toVal; i++)
{
PrepareNewEmployees(...);
decimal ratio = ((double)toVal-i)/(toVal-fromVal) *100;
//Some other things, that need to be done twice in an iteration
}
Because you are using Thread's already, consider to implement following:
public void ResetProgress()
{
SetProgress(0);
}
public SetProgress(int percents)
{
// set progress bar to a given percents/ratio
// you will have to use Invoke and blablabla
}
Then any your job will looks like this
ResetProgress();
// note: you need to remember from which value you start to be able to calculate progress
for (int i = startVal; i < toVal ; i++)
{
PrepareNewEmployees(calcYear, i);
SetProgress(100 * (i - startVal) / (toVal - startVal)); // in percents [0-100]
}
// optional, required if you exit loop or use suggestion below
SetProgress(100);
You can also optimise it, to do not update progress after each step, but after certain numbers of steps. To example, instead of calling SetProgress you do
if(i % 10 == 0)
SetProgress();
This will calls SetProgress ten times less often. Of course, there are some assumptions, like: i starts from 0 and if you want to have 100% bar at the end, then i should be dividable by 10. Just an idea to start.

How to create pulsating value from 0..1..0..1..0 etc for a given duration?

I'm working on some code where I have a Time object with a member time. Time.time gives
me the time since my application started in seconds (float value). Now I want to create a pulsating value between 0 and 1 and then from 1 to 0 again, which continues doing thins untill the application stops.
I was thinking to use sin() but don't know what to pass to it as paramters to create this pulsing value.
How would I create this pulsating value?
Kind regards,
Pollux
You mention using sin(), so I guess you want it to pulse continuously between 0 and 1.
Something like this will do:
float pulse(float time) {
const float pi = 3.14;
const float frequency = 10; // Frequency in Hz
return 0.5*(1+sin(2 * pi * frequency * time));
}
1/frequency = 0.1 second is the period, which is the time between 1's.
How about x = 1 - x?
Or if you want it to be time based use Timer % 2
Oh, you wanted the values between 0 and 1 as well.
how about Math.Abs(100 - (Timer % 200)) / 100
Where timer is something like DateTime.Now.TimeOfDay.TotalMilliseconds
Edit:
My tests indicate that this is more than twice as fast as the Sin method. For 1 million iterations, the sin method takes .048 seconds while the Abs method takes about .023 seconds. Also, you get different waveforms out of the two, of course. Sin produces a Sine wave, while Abs produces a triangular wave.
static void Main(string[] args)
{
System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
sw.Start();
const int count = 1000000;
float[] results = new float[count];
for (int i = 0; i < count; i++)
{
results[i] = AbsPulse(i/1000000F);
//results[i] = SinPulse(i / 1000000F);
}
sw.Stop();
Console.WriteLine("Time Elapsed: {0} seconds", sw.Elapsed.TotalSeconds);
char[,] graph = new char[80, 20];
for (int y = 0; y <= graph.GetUpperBound(1); y++)
for (int x = 0; x <= graph.GetUpperBound(0); x++)
graph[x, y] = ' ';
for (int x = 0; x < count; x++)
{
int col = x * 80 / count;
graph[col, (int)(results[x] * graph.GetUpperBound(1))] = 'o';
}
for (int y = 0; y <= graph.GetUpperBound(1); y++)
{
for (int x = 0; x < graph.GetUpperBound(0); x++)
Console.Write(graph[x, y]);
Console.WriteLine();
}
}
static float AbsPulse(float time)
{
const int frequency = 10; // Frequency in Hz
const int resolution = 1000; // How many steps are there between 0 and 1
return Math.Abs(resolution - ((int)(time * frequency * 2 * resolution) % (resolution * 2))) / (float)resolution;
}
static float SinPulse(float time)
{
const float pi = 3.14F;
const float frequency = 10; // Frequency in Hz
return 0.5F * (1 + (float)Math.Sin(2 * pi * frequency * time));
}
A sine function would be ideal I think, but you need to adjust the period and the scale.
The sine function produces results between -1 and 1, but you want to go between 0 and 1. To scale it properly you want (sin(x)+1)/2.
The sine function starts at zero, goes to 1 at pi/2, zero again at pi, -1 at 3*pi/2, and back to zero at 2*pi. Scaled, the first zero will happen at 3*pi/2 and the first maximum after that will be at 5/2*pi. So x in the previous formula is (2*time + 3) * pi/2.
Putting it all together: (sin((2*time.time + 3) * pi/2) + 1) / 2
How often do you want it to pulse?
Let's say you want to go from 0 to 1 over 10 seconds.
float pulseValueForTime(int sec) {
int pulsePoint = sec % 10;
float pulsePercent = (float)pulsePoint / (float)10;
float pulseInTermsOfPI = (pulsePercent * 2 * PI) - PI;
float sinVal = MagicalSinFunction(pulseInTermsOfPI); // what framework you use to compute sin is up to you... I'm sure you can google that!
return (sinVal + 1) / 2; // sin is between 1 and -1, translate to between 0 and 1
}
Look into Ease functions. They do this sort of thing in all sorts of manners - linear, poly, exp, sin, etc.

Categories