How can I make threads that do 1/4 of a function? - c#

I'm having an application that calculates the prime numbers of the user input. so if the user puts 10 in the console. Then it will show every prime number from 0 to 10. Now If I do something like 10000000 it will take a long time before it shows every prime number so I want to divide it by 4 threads, so that each thread can do 1/4 of the total number. So the first thread does from 0 till 250000, the second thread does the calculations from 250000 till 500000, etc. this is my code so far, what I'm doing with this code now is that I have 1 thread that calculates the prime of the number that the user puts in and in the end I'm making a sum of the values in the array.
using System;
using System.Diagnostics;
using System.Linq;
using System.Threading;
namespace WeekOpdr__5
{
internal class Program
{
static int[] deel1 = new int[10000];
static int n;
static int startNumber;
static int secondNumber;
static void Main(string[] args)
{
Stopwatch sw = new Stopwatch();
while (true)
{
Console.WriteLine("type a number in: ");
n = Convert.ToInt32(Console.ReadLine());
int start1 = 2;
int threadCount = 4;
var threads = new Thread[threadCount];
sw.Start();
for (int i = 0; i < threadCount; i++)
{
int range = n / threadCount * 2;
Console.WriteLine(range);
secondNumber = n / 2;
int start2 = start1;
threads[i] = new Thread(() => PrimeNumbers(startNumber, range ));
//threads[i] = new Thread(() => PrimeNumbers(secondNumber, n));
threads[i].Start();
}
for (int i = 0; i < threadCount; i++)
{
threads[i].Join();
}
Console.WriteLine($"The Prime Numbers between 0 and {n} are : ");
sw.Restart();
ReturnN();
SumN();
long timeElapsed = sw.ElapsedMilliseconds;
Console.WriteLine($"\nthe total time is {timeElapsed} ms");
}
static void PrimeNumbers(int startNumber, int n)
{
int position = 0;
for (int i = startNumber; i <= n; i++)
{
bool primeDetected = true;
for (int j = 2; j <= i / 2; j++)
{
if (i % j == 0)
{
primeDetected = false;
break;
}
}
if (primeDetected && i != 1)
{
deel1[position++] = i;
}
}
}
static void ReturnN()
{
foreach (int i in deel1)
{
Console.Write($"{i} ");
}
}
static void SumN()
{
int sum = deel1.Sum();
Console.WriteLine($"\nDe som van de priemgetallen tussen 2 en {n}: {sum}");
}
}
}
}

Related

Ryzen vs. i7 Multi-Threaded Performance

I made the following C# Console App:
class Program
{
static RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
public static ConcurrentDictionary<int, int> StateCount { get; set; }
static int length = 1000000000;
static void Main(string[] args)
{
StateCount = new ConcurrentDictionary<int, int>();
for (int i = 0; i < 3; i++)
{
StateCount.AddOrUpdate(i, 0, (k, v) => 0);
}
Console.WriteLine("Processors: " + Environment.ProcessorCount);
Console.WriteLine("Starting...");
Console.WriteLine();
Timer t = new Timer(1000);
t.Elapsed += T_Elapsed;
t.Start();
Stopwatch sw = new Stopwatch();
sw.Start();
Parallel.For(0, length, (i) =>
{
var rand = GetRandomNumber();
int newState = 0;
if(rand < 0.3)
{
newState = 0;
}
else if (rand < 0.6)
{
newState = 1;
}
else
{
newState = 2;
}
StateCount.AddOrUpdate(newState, 0, (k, v) => v + 1);
});
sw.Stop();
t.Stop();
Console.WriteLine();
Console.WriteLine("Total time: " + sw.Elapsed.TotalSeconds);
Console.ReadKey();
}
private static void T_Elapsed(object sender, ElapsedEventArgs e)
{
int total = 0;
for (int i = 0; i < 3; i++)
{
if(StateCount.TryGetValue(i, out int value))
{
total += value;
}
}
int percent = (int)Math.Round((total / (double)length) * 100);
Console.Write("\r" + percent + "%");
}
public static double GetRandomNumber()
{
var bytes = new Byte[8];
rng.GetBytes(bytes);
var ul = BitConverter.ToUInt64(bytes, 0) / (1 << 11);
Double randomDouble = ul / (Double)(1UL << 53);
return randomDouble;
}
}
Before running this, the Task Manager reported <2% CPU usage (across all runs and machines).
I ran it on a machine with a Ryzen 3800X. The output was:
Processors: 16
Total time: 209.22
The speed reported in the Task Manager while it ran was ~4.12 GHz.
I ran it on a machine with an i7-7820HK The output was:
Processors: 8
Total time: 213.09
The speed reported in the Task Manager while it ran was ~3.45 GHz.
I modified Parallel.For to include the processor count (Parallel.For(0, length, new ParallelOptions() { MaxDegreeOfParallelism = Environment.ProcessorCount }, (i) => {code});). The outputs were:
3800X: 16 - 158.58 # ~4.13
7820HK: 8 - 210.49 # ~3.40
There's something to be said about Parallel.For not natively identifying the Ryzen processors vs cores, but setting that aside, even here the Ryzen performance is still significantly poorer than would be expected (only ~25% faster with double the cores/processors, a faster speed, and larger L1-3 caches). Can anyone explain why?
Edit: Following a couple of comments, I made some changes to my code. See below:
static int length = 1000;
static void Main(string[] args)
{
StateCount = new ConcurrentDictionary<int, int>();
for (int i = 0; i < 3; i++)
{
StateCount.AddOrUpdate(i, 0, (k, v) => 0);
}
var procCount = Environment.ProcessorCount;
Console.WriteLine("Processors: " + procCount);
Console.WriteLine("Starting...");
Console.WriteLine();
List<double> times = new List<double>();
Stopwatch sw = new Stopwatch();
for (int m = 0; m < 10; m++)
{
sw.Restart();
Parallel.For(0, length, new ParallelOptions() { MaxDegreeOfParallelism = procCount }, (i) =>
{
for (int j = 0; j < 1000000; j++)
{
var rand = GetRandomNumber();
int newState = 0;
if (rand < 0.3)
{
newState = 0;
}
else if (rand < 0.6)
{
newState = 1;
}
else
{
newState = 2;
}
StateCount.AddOrUpdate(newState, 0, (k, v) => v + 1);
}
});
sw.Stop();
Console.WriteLine("Total time: " + sw.Elapsed.TotalSeconds);
times.Add(sw.Elapsed.TotalSeconds);
}
Console.WriteLine();
var avg = times.Average();
var variance = times.Select(x => (x - avg) * (x - avg)).Sum() / times.Count;
var stdev = Math.Sqrt(variance);
Console.WriteLine("Average time: " + avg + " +/- " + stdev);
Console.ReadKey();
Console.ReadKey();
}
The outside loop is 1,000 instead of 1,000,000,000, so there are "only" 1,000 parallel "tasks." Within each parallel "task" however there's now a loop of 1,000,000 actions, so the act of "getting the task" or whatever should have a much smaller affect on the total. I also loop the whole thing 10 times and get the average + standard devation. Output:
Ryzen 3800X: 158.531 +/- 0.429 # ~4.13
i7-7820HK: 202.159 +/- 2.538 # ~3.48
Even here, the Ryzen's twice as many threads and 0.60 GHz higher clock only result in a ~75% faster time for the total operation.

Find the largest palindrome made from the product of two 3-digit numbers C#

I tried to solve projecteuler 4th project with C# but I don't receive the correct answer, I get 90909. Can someone spot my mistake?
The problem goes like this:
A palindromic number reads the same both ways. The largest palindrome made from the product of two 2-digit numbers is 9009 = 91 × 99.
Find the largest palindrome made from the product of two 3-digit numbers.
namespace Largest_palindrome_product{
class Program
{
static void Main(string[] args)
{
string Reverse(string s)
{
char[] charArray = s.ToCharArray();
Array.Reverse(charArray);
return new string(charArray);
}
int result = 0;
string rev= "hello";
string palindrome = "hello";
string bingo = "hello";
int j = 1;
for (int i = 1; i< 1000; i++)
{
for (int y = 1; y< 1000; y++)
{
result = i * y;
bingo = result.ToString();
rev = Reverse(bingo);
j = int.Parse(bingo);
}
if (rev == bingo)
{
palindrome = bingo;
}
}
Console.Write(palindrome);
Console.Read();
}
}
}
I think what has caused so much confusion is the use of String this just complicates thing having to convert them back and forth.
Your program works fine (if the if is moved as per John's comment) if only you'd checked the new number was larger!
here is my take on it:
// stolen from https://www.geeksforgeeks.org/reverse-digits-integer-overflow-handled/
int Reverse(int num)
{
int rev_num = 0;
while (num > 0)
{
rev_num = rev_num * 10 + num % 10;
num = num / 10;
}
return rev_num;
}
int result = 0;
int palindrome = 0;
int j = 1;
for (int i = 999; i > 0; i--)
{
for (int y = 999; y > 0; y--)
{
result = i * y;
if (result == Reverse(result))
{
if (result > palindrome)
{
palindrome = result;
}
}
}
}
Console.Write(palindrome);
Console.Read();

Method Completely Ignores for loops:

After running my program I noticed that all values of my array are equal to one and after running the debugger I noticed that my for loops that should have populated the array are simply skipped over but I have absolutly no idea as to why. Could someone please tell me what I've done wrong?
The program reaches this line:
for (a = a; a >= 1000; a++) // Adds all prime numbers 1 through 1000 to primeA[];
and then jumps to:
for (int k = 0; k < primeA.Length; k++)
Complete code:
class calcPrime
{
/* #Method: isPrimeSET
* #param: int a, int b
* #return: true / false
* # Builds a list of primes and sorts them into a multi dimensional array.
*/
public int[,] isPrimeSet(int a, int b)
{
int[,] primeNumArray = new int[999, 999]; // Prime Multi Array 1000 slots in each array
int[] primeA = new int[999]; // All prime numbers a 1 to 1000
int[] primeB = new int[999]; // All prime numbers b 1 to 1000
ArrayList dumpArrayA = new ArrayList(); // None prime numbers
ArrayList dumpArrayB = new ArrayList(); // None prime numbers
for (a = a; a >= 1000; a++) // Adds all prime numbers 1 through 1000 to primA[];
{
if (isPrime(a) == true)
{
int i = 0; // Index of primeA
primeA[i] = a; // Add primes to a
i++;
}
else // Stores none prime numbers
{
int m = 0;
dumpArrayA.Add(m);
m++;
}
for (b = b; b >= 1000; b++) // Adds all prime number 1 through 1000 to primeB[];
{
if (isPrime(b) == true)
{
int j = 0; // Index of primeB
primeB[j] = b; // Add primes to b
j++;
}
else
{
int n = 0;
dumpArrayB.Add(n);
n++;
}
}
}
// Merge primesA[] and primesB[];
for (int k = 0; k < primeA.Length; k++)
{
primeNumArray[k, 0] = primeA[k];
primeNumArray[k, 1] = primeB[k];
}
// Print Contents of PrimeNumArray
for (int l = 0; l >= primeNumArray.Length; l++) {
Console.WriteLine(primeNumArray[l, l]);
}
return primeNumArray;
}
Else statements and dump arrays added in vain attempt at making the program work. Also I know I assigned a variable to the same variable in the for loops, I wanted the value to be set wherever the user chooses when the method is called.
There are many mistake there !!
I managed to correct your code
here is your corrected code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
namespace Prime_number
{
class Program
{
static void Main(string[] args)
{
int[,] k = isPrimeSet(1, 1);
Console.Read();
}
public static int[,] isPrimeSet(int a, int b)
{
int[,] primeNumArray; // Prime Multi Array 1000 slots in each array
ArrayList primeA = new ArrayList(); // All prime numbers a 1 to 1000
ArrayList primeB = new ArrayList(); // All prime numbers b 1 to 1000
ArrayList dumpArrayA = new ArrayList(); // None prime numbers
ArrayList dumpArrayB = new ArrayList(); // None prime numbers
int i = 0;
int m = 0;
int j = 0; // Index of primeB
int n = 0;
for (a = 1; a <= 1000; a++) // Adds all prime numbers 1 through 1000 to primA[];
{
if (isPrime(a) == true)
{
// Index of primeA
primeA.Add( a); // Add primes to a
i++;
}
else // Stores none prime numbers
{
dumpArrayA.Add(m);
m++;
}
}
for (b = 1; b <= 1000; b++) // Adds all prime number 1 through 1000 to primeB[];
{
if (isPrime(b) == true)
{
primeB.Add(b); // Add primes to b
j++;
}
else
{
dumpArrayB.Add(n);
n++;
}
}
primeNumArray= new int[primeA.Count,2];
// Merge primesA[] and primesB[];
for (int k = 0; k < primeA.Count; k++)
{
primeNumArray[k, 0] = (int)primeA[k];
primeNumArray[k, 1] = (int)primeB[k];
}
// Print Contents of PrimeNumArray
for (int l = 0; l <= primeNumArray.GetLength(0)-1; l++)
{
Console.WriteLine(primeNumArray[l, 0] + " " + primeNumArray[l, 1]);
}
return primeNumArray;
}
static bool isPrime(int num)
{
bool bPrime = true;
int factor = num / 2;
int i = 0;
for (i = 2; i <= factor; i++)
{
if ((num % i) == 0)
bPrime = false;
}
return bPrime;
}
}
}
Give it a try :) ! Thanks
I think index of array seems incorrect,
if (isPrime(a) == true)
{
int i = 0; // Index of primeA
primeA[i] = a; // Add primes to a
i++;
}
Isn't that changing only primeA[0] value? And for primeB array
int j = 0; // Index of primeB
primeB[j] = b; // Add primes to b
j++;
Maybe you should define i and j out of loop.

Format a number based on a required number of decimal places *and* sig figs

Our scientific application allows the user to configure the number of significant figures and decimal places to use when displaying numeric values. The formatting is currently being done with this code:-
var sigFigFormatted = valueToConvert.ToString("G" + numberOfSigFigs);
var theFullyFormattedValue = Convert.ToDouble(sigFigFormatted)
.ToString("F" + numberOfDecimalPlaces);
I don't like all this conversion to/from strings, and can't help thinking there must be a more efficient solution?
Look at accepted answer for this question.
I've ported code from the accepted answer to C# and made some tests.
Code:
using System;
using System.Diagnostics;
using System.Linq;
namespace ConsoleApplication1
{
public static class NumericExtensions
{
public static double RoundToSignificantFigures(this double num, int n)
{
if (num == 0)
{
return 0;
}
double magnitude = Math.Pow(10, n - (int)Math.Ceiling(Math.Log10(Math.Abs(num))));
double shifted = Math.Round(num * magnitude);
return shifted / magnitude;
}
public static double RoundToSignificantFiguresWithConvert(this double num, int n)
{
var sigFigFormatted = num.ToString("G" + n.ToString());
return Convert.ToDouble(sigFigFormatted);
}
}
class Program
{
static string[] Test1(double[] numbers, int numberOfSigFigs, int numberOfDecimalPlaces)
{
var result = new string[numbers.Length];
for (int i = 0; i < numbers.Length; i++)
{
result[i] = numbers[i].RoundToSignificantFigures(numberOfSigFigs).ToString("F" + numberOfDecimalPlaces.ToString());
}
return result;
}
static string[] Test2(double[] numbers, int numberOfSigFigs, int numberOfDecimalPlaces)
{
var result = new string[numbers.Length];
for (int i = 0; i < numbers.Length; i++)
{
result[i] = numbers[i].RoundToSignificantFiguresWithConvert(numberOfSigFigs).ToString("F" + numberOfDecimalPlaces.ToString());
}
return result;
}
static void Main(string[] args)
{
// create an array or random numbers
var rng = new Random();
var numbers = new double[100000];
for (int i = 0; i < numbers.Length; i++)
{
numbers[i] = 10000000000000000000D * (rng.NextDouble() - 0.5D);
}
const int numberOfSigFigs = 3;
const int numberOfDecimalPlaces = 3;
// make first run without time measurement
Test1(numbers, numberOfSigFigs, numberOfDecimalPlaces);
Test2(numbers, numberOfSigFigs, numberOfDecimalPlaces);
const int numberOfIterations = 100;
var sw = new Stopwatch();
sw.Start();
for (int i = 0; i < numberOfIterations; i++)
{
Test1(numbers, numberOfSigFigs, numberOfDecimalPlaces);
}
sw.Stop();
Console.WriteLine("Test1 elapsed {0} ms", sw.ElapsedMilliseconds.ToString());
sw.Restart();
for (int i = 0; i < numberOfIterations; i++)
{
Test2(numbers, numberOfSigFigs, numberOfDecimalPlaces);
}
sw.Stop();
Console.WriteLine("Test2 elapsed {0} ms", sw.ElapsedMilliseconds.ToString());
Console.ReadKey();
}
}
}
Results:
Test1 elapsed 7259 ms
Test2 elapsed 12918 ms
So NumericExtensions.RoundToSignificantFigures shows more efficient way of formating numbers.

Need to optimise counting positive and negative values

I need to optimise code that counts pos/neg values and remove non-qualified values by time.
I have queue of values with time-stamp attached.
I need to discard values which are 1ms old and count negative and positive values. here is pseudo code
list<val> l;
v = q.dequeue();
deleteold(l, v.time);
l.add(v);
negcount = l.count(i => i.value < 0);
poscount = l.count(i => i.value >= 0);
if(negcount == 10) return -1;
if(poscount == 10) return 1;
I need this code in c# working with max speed. No need to stick to the List. In fact arrays separated for neg and pos values are welcome.
edit: probably unsafe arrays will be the best. any hints?
EDIT: thanks for the heads up.. i quickly tested array version vs list (which i already have) and the list is faster: 35 vs 16 ms for 1 mil iterations...
Here is the code for fairness sake:
class Program
{
static int LEN = 10;
static int LEN1 = 9;
static void Main(string[] args)
{
Var[] data = GenerateData();
Stopwatch sw = new Stopwatch();
for (int i = 0; i < 30; i++)
{
sw.Reset();
ArraysMethod(data, sw);
Console.Write("Array: {0:0.0000}ms ", sw.ElapsedTicks / 10000.0);
sw.Reset();
ListMethod(data, sw);
Console.WriteLine("List: {0:0.0000}ms", sw.ElapsedTicks / 10000.0);
}
Console.ReadLine();
}
private static void ArraysMethod(Var[] data, Stopwatch sw)
{
int signal = 0;
int ni = 0, pi = 0;
Var[] n = new Var[LEN];
Var[] p = new Var[LEN];
for (int i = 0; i < LEN; i++)
{
n[i] = new Var();
p[i] = new Var();
}
sw.Start();
for (int i = 0; i < DATALEN; i++)
{
Var v = data[i];
if (v.val < 0)
{
int x = 0;
ni = 0;
// time is not sequential
for (int j = 0; j < LEN; j++)
{
long diff = v.time - n[j].time;
if (diff < 0)
diff = 0;
// too old
if (diff > 10000)
x = j;
else
ni++;
}
n[x] = v;
if (ni >= LEN1)
signal = -1;
}
else
{
int x = 0;
pi = 0;
// time is not sequential
for (int j = 0; j < LEN; j++)
{
long diff = v.time - p[j].time;
if (diff < 0)
diff = 0;
// too old
if (diff > 10000)
x = j;
else
pi++;
}
p[x] = v;
if (pi >= LEN1)
signal = 1;
}
}
sw.Stop();
}
private static void ListMethod(Var[] data, Stopwatch sw)
{
int signal = 0;
List<Var> d = new List<Var>();
sw.Start();
for (int i = 0; i < DATALEN; i++)
{
Var v = data[i];
d.Add(new Var() { time = v.time, val = v.val < 0 ? -1 : 1 });
// delete expired
for (int j = 0; j < d.Count; j++)
{
if (v.time - d[j].time < 10000)
d.RemoveAt(j--);
else
break;
}
int cnt = 0;
int k = d.Count;
for (int j = 0; j < k; j++)
{
cnt += d[j].val;
}
if ((cnt >= 0 ? cnt : -cnt) >= LEN)
signal = 9;
}
sw.Stop();
}
static int DATALEN = 1000000;
private static Var[] GenerateData()
{
Random r = new Random(DateTime.Now.Millisecond);
Var[] data = new Var[DATALEN];
Var prev = new Var() { val = 0, time = DateTime.Now.TimeOfDay.Ticks};
for (int i = 0; i < DATALEN; i++)
{
int x = r.Next(20);
data[i] = new Var() { val = x - 10, time = prev.time + x * 1000 };
}
return data;
}
class Var
{
public int val;
public long time;
}
}
To get negcount and poscount, you are traversing the entire list twice.
Instead, traverse it once (to compute negcount), and then poscount = l.Count - negcount.
Some ideas:
Only count until max(negcount,poscount) becomes 10, then quit (no need to count the rest). Only works if 10 is the maximum count.
Count negative and positive items in 1 go.
Calculate only negcount and infer poscount from count-negcount which is easier to do than counting them both.
Whether any of them are faster than what you have now, and which is fastest, depends among other things on what the data typically looks like. Is it long? Short?
Some more about 3:
You can use trickery to avoid branches here. You don't have to test whether the item is negative, you can add its negativity to a counter. Supposing the item is x and it is an int, x >> 31 is 0 for positive x and -1 for negative x. So counter -= x >> 31 will give negcount.
Edit: unsafe arrays can be faster, but shouldn't be in this case, because the loop would be of the form
for (int i = 0; i < array.Length; i++)
do something with array[i];
Which is optimized by the JIT compiler.

Categories