Why my parallel for loop is much slower than for? - c#

I tried changing my for loop with a parallel one but it's soo much slower instead of finishing the loop in a minute it finishes in 30 minutes. What the loop does is start with a number check if it's odd and if it's even. If it's odd it multiples by 3 and adds 1. If it's even it divides it by 2. Keep repeating that until the number reaches 4, and there is a loop around that repeats that a million times each time with a number higher by one. The last loop I mentioned is the loop I try to change to a parallel one. Here is the code for the normal for loop:
static void Main(string[] args)
{
BigInteger currenthighest =new BigInteger(Math.Pow(2,68));
BigInteger currentValue;
Console.WriteLine(currenthighest);
Console.ReadKey();
for (int i = 1; i > -1; i++)
{
for (int z = 0; z != 1000000; z++)
{
currentValue = currenthighest;
while (currentValue != 4)
{
if (currentValue % 2 == 0)
{
currentValue = currentValue / 2;
}
else
{
currentValue = (currentValue * 3) + 1;
}
}
currenthighest++;
}
Console.WriteLine(" {0} times done", i * 1000000);
}
}
And here is the code for the parallel one:
static void Main(string[] args)
{
BigInteger currenthighest =new BigInteger(Math.Pow(2,68));
BigInteger currentValue;
Console.WriteLine(currenthighest);
Console.ReadKey();
for (int i = 1; i > -1; i++)
{
Parallel.For(0, 1000000,z=>
{
currentValue = currenthighest;
while (currentValue != 4)
{
if (currentValue % 2 == 0)
{
currentValue = currentValue / 2;
}
else
{
currentValue = (currentValue * 3) + 1;
}
}
currenthighest++;
});
Console.WriteLine(" {0} times done", i * 1000000);
}
}
Can someone help me make it faster than a normal for loop or is using parallel in this situation stupid and I should just use normal for loop? If I will also appreciate any help to make normal for loop faster.

The reason for the performance deficit if as Theodor Zoulias points out probably due to it not being thread-safe. This can cause numbers to take arbitrary values and may cause totally different calculations to be performed.
To fix this you need to make each parallel loop independent. As far as I can tell this would be rather easy to do in your example since you only need to ensure that all modified values are local:
static void Main(string[] args)
{
BigInteger startvalue =new BigInteger(Math.Pow(2,68));
Console.WriteLine(startvalue );
Console.ReadKey();
for (int i = 1; i > -1; i++)
{
Parallel.For(0, 1000000,z=>
{
var currentValue = startvalue + z;
while (currentValue != 4)
{
if (currentValue % 2 == 0)
{
currentValue = currentValue / 2;
}
else
{
currentValue = (currentValue * 3) + 1;
}
}
});
Console.WriteLine(" {0} times done", i * 1000000);
}
}
Another possibility is that the work inside the parallel loop is on average quite small, causing the threading overhead to be significant. There is also the issue of work-balancing, Parallel.For will do work in 'chunks' to reduce this threading overhead, and try to adapt the size of these chunks. If the amount of work is highly variable this adaptation will probably result in inefficiencies.

Related

Detection a two different math cases using c#

I have this code that should run "Amount" times. The code has to do a math equation called
collatz conjecture, how it works is you get a number, if its odd you have to * by 3 and than add 1 but if its even you have to divide it by 2, this should go on until the number hits one, if the number does it one the variable Ver should be added but one otherwise this should get in a never ending loop, The problem is I don't know how to detect that loop. The code bellow is the whole thing without the loop detection and when I run it 1 million times it worked fine expect 432 numbers specifically that should not get in that loop.
The problem is you never know if the math equation is still happening or is it a special case that will never hit the number 1.
using System.Collections.Generic;
using System;
int Amount = 1000000;
int Ver = 0;
Amount++;
for (int i = 1; i < Amount; i++)
{
int i2 = i;
while (i2 > 1)
{
if (i2 % 2 == 0) {
int i3 = i2 / 2;
i2 = i3;
}
else
{
i2 = (i2 * 3) + 1;
}
}
if (i2 == 1 || i2==4 || i2==2)
Ver++;
}
Amount--;
Console.WriteLine(Ver + " of "+ Amount + " numbers were verified.");
A good idea would be if the program was stuck on number for too long (More than 2 or 3 minuets) to Maybe ask in the console to see if the program should continue on a number or should it skip that number. I have tried putting on timer each time it gets to a new number but it will slow the program by almost 3 or 4 times. Does anyone know a faster way to do that?
This solution does not pretend to be academic.
Due to link you provided you must use ulong (UInt64) at least instead of int (Int32)
You can use TPL DataFlow with CancellationToken:
using System.Collections.Concurrent;
using System.Threading.Tasks.Dataflow;
const ulong start = 20_000_001;
const ulong amount = 10_000_000;
const ulong maxIterations = 1000_0000;
ulong verified = 0;
ConcurrentBag<ulong> canceledNumbers = new ConcurrentBag<ulong>();
ConcurrentBag<ulong> overflowNumbers = new ConcurrentBag<ulong>();
var actionBlock = new ActionBlock<ulong>(CollatzAction,
new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = Environment.ProcessorCount * 2, // Remove 2 if you don't have hyperthreading
BoundedCapacity = Environment.ProcessorCount * 4, // Back pressure to avoid the memory overhead
});
for (ulong i = start; i < start + amount; i++)
{
await actionBlock.SendAsync(i).ConfigureAwait(false);
}
actionBlock.Complete();
await actionBlock.Completion.ConfigureAwait(false);
Console.WriteLine($"{verified} of {amount} numbers were verified, {canceledNumbers.Count} were canceled.");
if (!canceledNumbers.IsEmpty)
{
Console.WriteLine($"Canceled numbers are: {string.Join(", ", canceledNumbers)}");
}
if (!overflowNumbers.IsEmpty)
{
Console.WriteLine($"Overflow numbers are: {string.Join(", ", overflowNumbers)}");
}
void CollatzAction(ulong i)
{
try
{
var (oneIsReached, isCanceled) = Collatz(i);
if (oneIsReached)
{
Interlocked.Increment(ref verified);
}
else if (isCanceled)
{
canceledNumbers.Add(i);
}
}
catch (OverflowException)
{
overflowNumbers.Add(i);
}
}
(bool oneIsReached, bool isCanceled) Collatz(ulong i)
{
ulong iteration = 1;
while (i > 1 && iteration <= maxIterations)
{
i = (i & 1) == 0 // the same as i % 2 == 0 but faster
? i / 2
: checked(i * 3 + 1);
iteration++;
}
return (i == 1, iteration > maxIterations);
}
You can try to replace ulong with BigInteger to avoid overflows, but it's much slower:
using System.Collections.Concurrent;
using System.Numerics;
using System.Threading.Tasks.Dataflow;
BigInteger start = 100_000_001;
const ulong amount = 10_000_000;
const ulong maxIterations = 1000_0000;
ulong verified = 0;
ConcurrentBag<BigInteger> canceledNumbers = new ConcurrentBag<BigInteger>();
var actionBlock = new ActionBlock<BigInteger>(CollatzAction,
new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = Environment.ProcessorCount * 2, // Remove 2 if you don't have hyperthreading
BoundedCapacity = Environment.ProcessorCount * 4, // Back pressure to avoid the memory overhead
});
for (BigInteger i = start; i < start + amount; i++)
{
await actionBlock.SendAsync(i).ConfigureAwait(false);
}
actionBlock.Complete();
await actionBlock.Completion.ConfigureAwait(false);
Console.WriteLine($"{verified} of {amount} numbers were verified, {canceledNumbers.Count} were canceled.");
if (!canceledNumbers.IsEmpty)
{
Console.WriteLine($"Canceled numbers are: {string.Join(", ", canceledNumbers)}");
}
void CollatzAction(BigInteger i)
{
var (oneIsReached, isCanceled) = Collatz(i);
if (oneIsReached)
{
Interlocked.Increment(ref verified);
}
else if (isCanceled)
{
canceledNumbers.Add(i);
}
}
(bool oneIsReached, bool isCanceled) Collatz(BigInteger i)
{
ulong iteration = 1;
while (i > 1 && iteration <= maxIterations)
{
i = (i & 1) == 0 // the same as i % 2 == 0 but faster
? i / 2
: i * 3 + 1;
iteration++;
}
return (i == 1, iteration > maxIterations);
}

How to record counter while not removing calculation in test code

I have a method that increments every time the function is executed. However, from the recommendations I've been told that with compiler optimization turned on it ignores my calculation and just increments. Here is the link to my previously asked question.
private static void IntOp(object index)
{
long op = 0;
long intop = 0;
while (!stop)
{
intop = (op + 1) - 10 * 2;
op++;
}
operations[(int) index] = op;
}
How can I bypass this and still keep track of the number of times the operation has been performed?
You can trivially fix this by returning intop at the end of your method.
private static long IntOp(object index)
{
long op = 0;
long intop = 0;
while (!stop || intop < 100)
{
intop = (op + 1) - 10 * 2;
op++;
}
operations[(int)index] = op;
return intop;
}

Is there a more efficient method for omitting for loop instances

If I have a standard for loop is there a more efficient way to omit certain occurances?
For example:
A:
for (int i = 0; i < n; i++)
{
if (i != n / 2 && i != n / 3 && i != n / 4)
{
val += DoWork(i);
}
else
{
continue;
}
}
B:
for (int i = 0; i < n / 4; i++)
{
val += DoWork(i); ;
}
for (int i = n / 4 + 1; i < n / 3; i++)
{
val += DoWork(i);
}
for (int i = n / 3 + 1; i < n / 2; i++)
{
val += DoWork(i);
}
for (int i = n / 2 + 1; i < n; i++)
{
val += DoWork(i);
}
C:
for (int i = 0; i < n; i++)
{
if (i == n / 2 || i == n / 3 || i == n / 4)
{
continue;
}
else
{
val += DoWork(i);
}
}
For n = int.MaxValue the results were as follows:
A Results: 57498 milliseconds.
B Results: 42204 milliseconds.
C Results: 57643 milliseconds.
EDIT BASED ON #Churk 's answer.
I added another test case method D as follows:
D:
for (int i = 0; i < n; i = (i != n / 2 -1 && i != n / 3 -1 && i != n / 4-1) ? i+1: i+2)
{
val += DoWork(i);
}
and got the following results:
A Results: 56355 milliseconds.
B Results: 40612 milliseconds.
C Results: 56214 milliseconds.
D Results: 51810 milliseconds.
Edit2: After pre-calculating values for n/2 n/3 and n/4 outside the loop got:
A Results: 50873 milliseconds.
B Results: 39514 milliseconds.
C Results: 51167 milliseconds.
D Results: 42808 milliseconds.
The D loop seems to be close again to the "unrolling" of B, with A and C still taking significantly more time.
Which are about what I expected, as far as comparisons between each of the methods.
My question is, is there a more efficient way of doing this?
It depends a bit on the context. One possiblitiy in many scenarios is to cheat. So instead of omitting the numbers, just include them and later reverse the result from the numbers you didn't want:
for (int i = 0; i < n; i++)
{
val += DoWork(i);
}
val -= DoWork(i/2);
val -= DoWork(i/3);
val -= DoWork(i/4);
The time you save from comparisons might outweigh the results from calculating some numbers twice, depending on how expensive the DoWork operation is.
Embed your secondary condition into you for loop
Untested:
for (int i = 0; i < n || (i != n / 2 && i != n / 3 && i != n / 4); i++)
val += DoWork(i);
}
I think this will work as long as one of those condition is true it will keep going
First, just pause it a few times during that 40-60 seconds, so you get a fair idea what fraction of time is in DoWork. If you could even make your looping take no time at all, you'd still have to spend that part.
Now look at your comparisons.
Each one is asking a question.
If the answer to a question is almost always True or almost always False, it is an opportunity to get speedup.
(All the log(n) and n*log(n) algorithms work by making their decision points more like fair coins.)
So you can see why your B is faster. It is asking fewer questions per loop, on average.
You can make it even faster, by unrolling the loops (asking the questions even less often).
(I know, I know, compilers can unroll loops. Well, maybe. Do it yourself and you won't have to bet on it.)
You could calculate the values outside of the loop and then just skip them:
int skip1 = n/2;
int skip2 = n/3;
int skip3 = n/4;
for (int i = 0; i < n; i++)
{
if (i != skip1 && i != skip2 && i != skip3)
{
val += DoWork(i);
}
}
Not sure if this will save enough milliseconds to be worthwhile, though.
Update: I've just noticed that #surfen suggested this in the comments.
If DoWork() isn't the bottleneck, it is a small enough method to embed into the loop, so you won't need the call which costs time by itself. If DoWork() does most of the work though, you're the one wasting time :)
You can count operations...
Option A:
n checks on i in the for loop and then 3 checks on each i that isn't that value... so there's 4n operations just for the checks.
option B:
You're just looping through intervals, so you're doing n-3 operations.
option C:
Same as option A, 4n operations.
I wouldn't bother complicating code with such modifications (as many have already commented on your question)
Instead, you might want to run your DoWork simultanuously in multiple threads using Pararell.ForEach. This would have a much larger impact on performance, if your DoWork() does anything.

Fast prime numbers between range

I am trying to develop one program for develop very fast prime numbers. Prime numbers are to be generated in range (Range <= 10000) and the result should be printed in under 6 seconds. This is the program i have made so far. It runs just fine on my machine 1.73 core 2 duo and produces result in under 3 seconds. But when i submit it to online program submission validator it gives time limit exceeded. I have even removed try catch block etc as i thought removing try catch may save few resources and buy me few milliseconds, but no matter whatever i do i always get time limit exceeded. This is my code :-
using System;
using System.Collections.Generic;
using System.Linq;
namespace PrimeNumberGenerator
{
class Program
{
static void Main(string[] args)
{
int T = Convert.ToInt32(Console.ReadLine());
List<string> listInput = new List<string>();
for (int i = 0; i < T; i++)
listInput.Add(Console.ReadLine());
for (int i = 0; i < T; i++)
{
string[] str = listInput[i].Split(' ');
int M = Convert.ToInt32(str[0]);
int N = Convert.ToInt32(str[1]);
if ((N - M) <= 100000 && M >= 1 && M <= 1000000000 && N >= 1 && N <= 1000000000)
{
int[] list = Enumerable.Range(M, (N - M + 1)).ToArray();
int k = 2;
while (true)
{
if ((k * k) > N)
break;
for(int j = 0 ; j < list.Count() ;j++)
{
if (list[j] != k && (list[j] % k) == 0 && list[j] != 1 && list[j] != -1)
list[j] = -1;
}
k++;
}
foreach (int item in list)
{
if (item != -1)
Console.WriteLine(item);
}
}
else
Console.WriteLine("Limit exceeded");
}
}
}
}
You have to give input like this :-
1
2 30
1 is no of test case and 2 and 30 mean that all primes between 2 and 30 should be produced.
You can give it 1 if you are only testing it once. I will be very grateful if you can optimise this program
Thanks in advance :)
EDIT :-
This is the original implmentation that i thought but obviously has overhead of list :-
using System;
using System.Collections.Generic;
using System.Linq;
namespace PrimeNumberGenerator
{
class Program
{
static void Main(string[] args)
{
try
{
int T = Convert.ToInt32(Console.ReadLine());
List<string> listInput = new List<string>();
for (int i = 0; i < T; i++)
listInput.Add(Console.ReadLine());
for (int i = 0; i < T; i++)
{
string[] str = listInput[i].Split(' ');
int M = Convert.ToInt32(str[0]);
int N = Convert.ToInt32(str[1]);
List<int> list = null;
if ((N - M) <= 100000 && M >= 1 && M <= 1000000000 && N >= 1 && N <= 1000000000)
{
list = Enumerable.Range(M, (N - M + 1)).ToList();
int k = 2;
while (true)
{
if ((k * k) > N)
break;
List<int> tempList = new List<int>();
foreach (int item in list)
if (item != k && (item % k) == 0 && item != 1)
tempList.Add(item);
list = list.Except(tempList).ToList();
k++;
}
//list.Remove(1);
foreach (int item in list)
Console.WriteLine(item);
Console.WriteLine();
}
else
Console.WriteLine("Limit exceeded");
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.ReadKey();
}
}
}
All I can say is that looks like a lot of loops within loops you've got going on. Probably the main issue is just your general algorithm.
To test if a number is prime, it's sufficient to check whether it's evenly divisible by any number between 2 and its sqrt (rounded down).
But if you're checking many primes, you ought to leverage the fact that as you check higher and higher numbers you can start with only primes (I would store these in a simple List<int>). For example, say you've reached the number 27. You only need to check whether it's divisible by 2, 3, or 5 (the prime numbers you've already found less than sqrt(25) which is 5), not 4 (since 4 is divisible by 2—if it's divisible by 4, then it's divisible by 2), and not anything above that (if it's evenly divisible by anything above 5, the quotient will be below 5, and you would have already checked it).
Those are some general concepts that ought to help you optimize what looks upon first glance like a pretty inefficient algorithm.
There are three solutions to performance problems: benchmarks, benchmarks, benchmarks.
Use a profiler to benchmark your code. For C# I personally prefer ANTS Performance Profiler but there are also other options available.
I suggest you to update (or post another) your question with specific bottlenecks.
Your program is expected to output the numbers in 6 seconds(time-critical), so you should make full use of the memory in the 6 seconds to save time. For example, you can use multi-threading or parallel programming to generate numbers faster(more CPU/memory usages). Currently you are working in a regular way, which can't show off C#'s advantages(your code can be converted directly into C/Java/others with few changes). You need to do it in the C# way, otherwise why do you choose C#? Here is an example(non-tested, but I think it should be correct) which is much more in C# way.
int min = 2;
int max = 10000;
Enumerable.Range(min, max - min + 1)
.AsParallel()
.ForAll(g =>
{
bool prime = true;
for (int i = 2; i <= Math.Sqrt(g); i++)
{
if (g % i == 0)
{
prime = false;
break;
}
}
if (prime) Console.WriteLine(g);
});
EDIT: I just tested the code, primes less than 10000 are printed out in 0 seconds, measured by StopWatch.

C#, finding the largest prime factor of a number

I am new at programming and I am practicing my C# programming skills. My application is meant to find the largest prime factor of a number entered by the user. But my application is not returning the right answer and I dont really know where the problem is. Can you please help me?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Calcular máximo factor primo de n. De 60 es 5.");
Console.Write("Escriba un numero: ");
long num = Convert.ToInt64(Console.ReadLine());
long mfp = maxfactor(num);
Console.WriteLine("El maximo factor primo es: " + num);
Console.Read();
}
static private long maxfactor (long n)
{
long m=1 ;
bool en= false;
for (long k = n / 2; !en && k > 1; k--)
{
if (n % k == 0 && primo(k))
{
m = k;
en = true;
}
}
return m;
}
static private bool primo(long x)
{
bool sp = true;
for (long i = 2; i <= x / 2; i++)
{
if (x % i == 0)
sp = false;
}
return sp;
}
}
}
It will be much faster to remove the small factors until the residue is prime.
static private long maxfactor (long n)
{
long k = 2;
while (k * k <= n)
{
if (n % k == 0)
{
n /= k;
}
else
{
++k;
}
}
return n;
}
For example, if n = 784, this does 9 modulo operations instead of several hundred. Counting down even with the sqrt limit still would do 21 modulo ops just in maxfactor, and another dozen in primo.
New more optimized version here
Console.WriteLine("El maximo factor primo es: " + mfp);
instead of
Console.WriteLine("El maximo factor primo es: " + num);
you have condition (!en) that makes it iterate only until first prime factor. Also you can reduce bounds from n/2 to sqrt(n)+1
Catalin DICU already answered your question, but you've got some non-idiomatic constructs in your code that you should probably look at refactoring. For example, in your maxfactor method, you don't need the "en" condition, just return the value as soon as you've found it:
static private long maxfactor (long n)
{
for (long k = n / 2; k > 1; k--)
{
if (n % k == 0 && primo(k))
{
return k;
}
}
// no factors found
return 1;
}
Similarly for your primo method, you can just return false as soon as you find a factor.
here's a f# version for this:
let lpf n =
let rec loop n = function
|k when k*k >= n -> n
|k when n % k = 0I -> loop (n/k) k
|k -> loop n (k+1I)
loop n 2I
This runs for less than three seconds.
public static void Main()
{
int prime=1;
long n=600851475143;
for (long i=2;i<=n;i++)
{
while (n%i==0)
n=n/i;
prime++;
}
Console.WriteLine(prime);
Console.WriteLine("Hello World!");
Console.ReadKey();
}

Categories

Resources