Parallel factorial with multiple threads - c#

I'm trying to make a function that calculates factorial of a number in parallel, just for testing purposes.
Let's say I have 4 cores on my cpu, so I will split the "problem" in 4 chunks.
Saying that, I made this:
public class FactorialPTest
{
public static object _locker = new object();
public static long Factorial(int x)
{
long result = 1;
int right = 0;
int nr = x;
bool done = false;
for (int i = 0; i < nr; i += (nr / 4))
{
int step = i;
new Thread(new ThreadStart(() =>
{
right = (step + nr / 4) > nr ? nr : (step + nr / 4);
long chunkResult = ChunkFactorial(step + 1, right);
lock (_locker)
{
result *= chunkResult;
if (right == nr)
done = true;
}
})).Start();
}
while(!done)
{
Thread.Sleep(10);
}
return result;
}
public static long ChunkFactorial(int left, int right)
{
//Console.WriteLine("left: {0} ; right: {1}", left, right);
Console.WriteLine("ChunkFactorial Thread ID :" + Thread.CurrentThread.ManagedThreadId);
if (left == right)
return left == 0 ? 1 : left;
else return right * ChunkFactorial(left, right - 1);
}
public static void main()
{
Console.WriteLine(Factorial(15));
}
}
Sometimes is working, sometimes it gives me intermediary results and sometimes a deadlock happens.
Why is this happening? Shouldn't Thread.Sleep(10) pause the main thread until I get the final result ?

I'd suggest looking into the Task Parallel Library. Among other things it will abstract away a lot of the low concerns relating to multi-threading.
You can represent each chunk of work with a task, add to a collection and then wait for them all to finish:
public static long Factorial(int x)
{
long result = 1;
int right = 0;
int nr = x;
bool done = false;
var tasks = new List<Task>();
for (int i = 0; i < nr; i += (nr / 4))
{
int step = i;
tasks.Add(Task.Run(() =>
{
right = (step + nr / 4) > nr ? nr : (step + nr / 4);
long chunkResult = ChunkFactorial(step + 1, right);
lock (_locker)
{
result *= chunkResult;
}
}));
}
Task.WaitAll(tasks.ToArray());
return result;
}
In your original code the last chunk could conceivably complete it's work first and right would equal nr even though the other chunks hadn't been calculated. Also, right was getting shared between all the threads so this could also lead to some unpredictable results, i.e, all threads are trying to use this variable to hold different values at the same time.
Generally you should try to avoid sharing state between threads if possible. The code above could be improved by having each task return it's result and then use these results to calculate the final one:
public static long Factorial(int x)
{
int nr = x;
var tasks = new List<Task<long>>();
for (int i = 0; i < nr; i += (nr / 4))
{
int step = i;
tasks.Add(Task.Run(() =>
{
int right = (step + nr / 4) > nr ? nr : (step + nr / 4);
return ChunkFactorial(step + 1, right);
}));
}
Task.WaitAll(tasks.ToArray());
return tasks.Select(t => t.Result).Aggregate(((i, next) => i * next));
}

You could use one of the Parallel.For overloads with aggregation, it will handle parallelism, partitioning of the workload and aggregation of the results for you. For long type of result, you can only do factorial of 21, if I am not mistaken. It also makes sense to add checked {...} to catch overflows. The code could looks like:
public long CalculateFactorial(long value)
{
var result = 1L;
var syncRoot = new object();
checked
{
Parallel.For(
// always 1
1L,
// target value
value,
// if need more control, add { MaxDegreeOfParallelism = 4}
new ParallelOptions(),
// thread local result init
() => 1L,
// next value
(i, state, localState) => localState * i,
// aggregate local thread results
localState =>
{
lock (syncRoot)
{
result *= localState;
}
}
);
}
return result;
}
Hope this helps.

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);
}

Why my parallel for loop is much slower than for?

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.

To accelerate calculating of pi using TPL

I need to calculate Pi - number via Monte-Carlo method using Task Parallel Library, but when my paralleled program is running, it calculates Pi - number much longer than it's unparallel analog.How two fix it? Paralleled calculating class and it's unparallel analog are below:
class CalcPiTPL
{
Object randLock = new object();
int n;
int N_0;
double aPi;
public StringBuilder Msg; // diagonstic message
double x, y;
Stopwatch stopWatch = new Stopwatch();
public void Init(int aN)
{
stopWatch.Start();
n = aN; // save total calculate-iterations amount
aPi = -1; // flag, if no any calculate-iteration has been completed
Msg = new StringBuilder("No any calculate-iteration has been completed");
}
public void Run()
{
if (n < 1)
{
Msg = new StringBuilder("Inbalid N-value");
return;
}
Random rnd = new Random(); // to create randomizer
Task[] tasks = new Task[4];
tasks[0] = Task.Factory.StartNew(() => PointGenerator(n, rnd));
tasks[1] = Task.Factory.StartNew(() => PointGenerator(n, rnd));
tasks[2] = Task.Factory.StartNew(() => PointGenerator(n, rnd));
tasks[3] = Task.Factory.StartNew(() => PointGenerator(n, rnd));
Task.WaitAll(tasks[0], tasks[1], tasks[2], tasks[3]);
aPi = 4.0 * ((double)N_0 / (double)n); // to calculate approximate Pi - value
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
ts.Hours, ts.Minutes, ts.Seconds,
ts.Milliseconds / 10);
Console.WriteLine("RunTime " + elapsedTime);
}
public double Done()
{
if (aPi > 0)
{
Msg = new StringBuilder("Calculates has been completed successful");
return aPi; // return gotten value
}
else
{
return 0; // no result
}
}
public void PointGenerator(int n, Random rnd)
{
for (int i = 1; i <= n / 4; i++)
{
lock (randLock)
{
x = rnd.NextDouble(); // to generate coordinates
y = rnd.NextDouble(); //
if (((x - 0.5) * (x - 0.5) + (y - 0.5) * (y - 0.5)) < 0.25)
{
//Interlocked.Increment(ref N_0);
N_0++; // coordinate in a circle! mark it by incrementing N_0
}
}
}
}
}
Unparallel analog:
class TCalcPi//unparallel calculating method
{
int N;
int N_0;
double aPi;
public StringBuilder Msg; // diagnostic message
double x, y;
Stopwatch stopWatch = new Stopwatch();
public void Init(int aN)
{
stopWatch.Start();
N = aN; // save total calculate-iterations amount
aPi = -1; // flag, if no any calculate-iteration has been completed
Msg = new StringBuilder("No any calculate-iteration has been completed");
}
public void Run()
{
if (N < 1)
{
Msg = new StringBuilder("Invalid N - value");
return;
}
int i;
Random rnd = new Random(); // to create randomizer
for (i = 1; i <= N; i++)
{
x = rnd.NextDouble(); // to generate coordinates
y = rnd.NextDouble(); //
if (((x - 0.5) * (x - 0.5) + (y - 0.5) * (y - 0.5)) < 0.25)
{
N_0++; // coordinate in a circle! mark it by incrementing N_0
}
}
aPi = 4.0 * ((double)N_0 / (double)N); // to calculate approximate Pi - value
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
ts.Hours, ts.Minutes, ts.Seconds,
ts.Milliseconds / 10);
Console.WriteLine("RunTime " + elapsedTime);
}
public double Done()
{
if (aPi > 0)
{
Msg = new StringBuilder("Calculates has been completed successful");
return aPi; // return gotten value
}
else
{
return 0; // no result
}
}
}
You have written the PointGenerator in a way in which it can barely benefit from being executed in parallel.
the lock means it will have basically single-threaded performance with additional threading overhead
a global state N_0 means you will have to synchronize access. Granted, since it's just an int you can use the Interlocked class for efficiently incrementing it.
What I would is to let each PointGenerator have a different Random object and a different counter. Then there won't be any shared mutable state which could cause problems. Be careful though, the default constructor of Random uses the tick count of the system. Creating several objects might result in random generators with the same seed.
Once all PointGenerator finish you combine the results.
This would be very similar to what some of the TPL overloads of Parallel.For and Parallel.ForEach do.
I know this post is old but it still shows up when searching for how to compute pi in parallel in C#. I have modified this to use the systems thread count for the workers. Also the lock is not needed if we use a return type for the workers, put some of the other variables in the worker function and finally let everything be put together by yet another task. This uses long for a larger count of iterations. The instances of Random are created with the thread id as the seed, which i hope makes them give different sequences of random numbers. Removed the Init-Method and put initialization in the Run-Method instead. There are two ways of using this now, blocking and non-blocking. But first here is the class:
public class CalcPiTPL
{
private long n;
private double pi;
private Stopwatch stopWatch = new Stopwatch();
private Task<int>[]? tasks = null;
private Task? taskOrchestrator = null;
private ManualResetEvent rst = new ManualResetEvent(false);
private bool isDone = false;
public string elapsedTime = string.Empty;
public double Pi { get { return pi; } }
public void Run(long n)
{
if (n < 1 || taskOrchestrator!=null) return;
isDone = false;
rst.Reset();
stopWatch.Start();
this.n = n; // save total calculate-iterations amount
pi = -1; // flag, if no any calculate-iteration has been completed
tasks = new Task<int>[Environment.ProcessorCount];
for(int i = 0; i < Environment.ProcessorCount; i++)
{
tasks[i] = Task.Factory.StartNew(() => PointGenerator(n));
}
taskOrchestrator = Task.Factory.StartNew(() => Orchestrator());
}
private void Orchestrator()
{
Task.WaitAll(tasks);
long N_0 = 0;
foreach (var task in tasks)
{
N_0 += task.GetAwaiter().GetResult();
}
pi = 4.0 * ((double)N_0 / (double)n); // to calculate approximate Pi - value
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10);
tasks = null;
taskOrchestrator = null;
isDone = true;
rst.Set();
}
public double Wait()
{
rst.WaitOne();
return pi;
}
public bool IsDone()
{
return isDone;
}
private int PointGenerator(long n)
{
int N_0 = 0;
Random rnd = new Random(Thread.CurrentThread.ManagedThreadId);
for (int i = 1; i <= n / Environment.ProcessorCount; i++)
{
double x = rnd.NextDouble(); // to generate coordinates
double y = rnd.NextDouble(); //
if (((x - 0.5) * (x - 0.5) + (y - 0.5) * (y - 0.5)) < 0.25)
{
N_0++;
}
}
return N_0;
}
}
Blocking call:
CalcPiTPL pi = new CalcPiTPL();
pi.Run(1000000000);
Console.WriteLine(pi.Wait());
non-blocking call:
CalcPiTPL pi = new CalcPiTPL();
pi.Run(100000000);
while (pi.IsDone()==false)
{
Thread.Sleep(100);
// Do something else
}
Console.WriteLine(pi.Pi);
Adding an event would probably be nice, if someone wants to use this in a GUI application. Maybe i will do that later.
Feel free to correct, if i messed something up.
When your whole parallel part is inside a lock scope nothing is actually parallel. Only a single thread can be inside a lock scope in any given moment.
You can simply use different Random instances instead of a single one.

How can I prevent my Ackerman function from overflowing the stack?

Is there a way to keep my Ackerman function from creating a stack over flow is does it for relatively small numbers , i.e. (4,2). This is the error
{Cannot evaluate expression because the current thread is in a stack
overflow state.}
private void Button1Click(object sender, EventArgs e)
{
var t = Ackermann(4,2);
label1.Text += string.Format(": {0}", t);
label1.Visible = true;
}
int Ackermann(uint m, uint n)
{
if (m == 0)
return (int) (n+1);
if (m > 0 && n == 0)
return Ackermann(m - 1, 1);
if (m > 0 && n > 0)
return Ackermann(m - 1, (uint)Ackermann(m, n - 1));
else
{
return -1;
}
}
The best way to avoid StackOverflowException is to not use the stack.
Let's get rid of the negative case, as it's meaningless when we call with uint. Alternatively, what follows here will also work if we make the negative test the very first thing in the method, before the other possibilities are considered:
First, we're going to need a bigger boat:
public static BigInteger Ackermann(BigInteger m, BigInteger n)
{
if (m == 0)
return n+1;
if (n == 0)
return Ackermann(m - 1, 1);
else
return Ackermann(m - 1, Ackermann(m, n - 1));
}
Now success is at least mathematically possible. Now, the n == 0 case is a simple enough tail-call. Let's eliminate that by hand. We'll use goto because it's temporary so we don't have to worry about velociraptors or Dijkstra:
public static BigInteger Ackermann(BigInteger m, BigInteger n)
{
restart:
if (m == 0)
return n+1;
if (n == 0)
{
m--;
n = 1;
goto restart;
}
else
return Ackermann(m - 1, Ackermann(m, n - 1));
}
This will already take a bit longer to blow the stack, but blow it, it will. Looking at this form though, note that m is never set by the return of a recursive call, while n sometimes is.
Extending this, we can turn this into an iterative form, while only having to deal with tracking previous values of m, and where we would return in the recursive form, we assign to n in our iterative form. Once we run out of ms waiting to be dealt with, we return the current value of n:
public static BigInteger Ackermann(BigInteger m, BigInteger n)
{
Stack<BigInteger> stack = new Stack<BigInteger>();
stack.Push(m);
while(stack.Count != 0)
{
m = stack.Pop();
if(m == 0)
n = n + 1;
else if(n == 0)
{
stack.Push(m - 1);
n = 1;
}
else
{
stack.Push(m - 1);
stack.Push(m);
--n;
}
}
return n;
}
At this point, we have answered the OP's question. This will take a long time to run, but it will return with the values tried (m = 4, n = 2). It will never throw a StackOverflowException, though it will end up running out of memory above certain values of m and n.
As a further optimisation, we can skip adding a value to the stack, only to pop it immediately after:
public static BigInteger Ackermann(BigInteger m, BigInteger n)
{
Stack<BigInteger> stack = new Stack<BigInteger>();
stack.Push(m);
while(stack.Count != 0)
{
m = stack.Pop();
skipStack:
if(m == 0)
n = n + 1;
else if(n == 0)
{
--m;
n = 1;
goto skipStack;
}
else
{
stack.Push(m - 1);
--n;
goto skipStack;
}
}
return n;
}
This doesn't help us with stack nor meaningfully with heap, but given the number of loops this thing will do with large values, every bit we can shave off is worth it.
Eliminating goto while keeping that optimisation is left as an exercise for the reader :)
Incidentally, I got too impatient in testing this, so I did a cheating form that uses known properties of the Ackerman function when m is less than 3:
public static BigInteger Ackermann(BigInteger m, BigInteger n)
{
Stack<BigInteger> stack = new Stack<BigInteger>();
stack.Push(m);
while(stack.Count != 0)
{
m = stack.Pop();
skipStack:
if(m == 0)
n = n + 1;
else if(m == 1)
n = n + 2;
else if(m == 2)
n = n * 2 + 3;
else if(n == 0)
{
--m;
n = 1;
goto skipStack;
}
else
{
stack.Push(m - 1);
--n;
goto skipStack;
}
}
return n;
}
With this version, I can get a result of true for Ackermann(4, 2) == BigInteger.Pow(2, 65536) - 3 after a little over a second (Mono, Release build, running on a Core i7). Given that the non-cheating version is consistent in returning the correct result for such values of m, I take this as reasonable evidence of the correctness of the previous version, but I'll leave it running and see.
Edit: Of course, I'm not really expecting the previous version to return in any sensible timeframe, but I thought I'd leave it running anyway and see how its memory use went. After 6 hours it's sitting nicely under 40MiB. I'm pretty happy that while clearly impractical, it would indeed return if given enough time on a real machine.
Edit: Apparently it's being argued that Stack<T> hitting its internal limit of 2³¹ items counts as a sort of "stack overflow", too. We can deal with that also if we must:
public class OverflowlessStack <T>
{
internal sealed class SinglyLinkedNode
{
//Larger the better, but we want to be low enough
//to demonstrate the case where we overflow a node
//and hence create another.
private const int ArraySize = 2048;
T [] _array;
int _size;
public SinglyLinkedNode Next;
public SinglyLinkedNode()
{
_array = new T[ArraySize];
}
public bool IsEmpty{ get{return _size == 0;} }
public SinglyLinkedNode Push(T item)
{
if(_size == ArraySize - 1)
{
SinglyLinkedNode n = new SinglyLinkedNode();
n.Next = this;
n.Push(item);
return n;
}
_array [_size++] = item;
return this;
}
public T Pop()
{
return _array[--_size];
}
}
private SinglyLinkedNode _head = new SinglyLinkedNode();
public T Pop ()
{
T ret = _head.Pop();
if(_head.IsEmpty && _head.Next != null)
_head = _head.Next;
return ret;
}
public void Push (T item)
{
_head = _head.Push(item);
}
public bool IsEmpty
{
get { return _head.Next == null && _head.IsEmpty; }
}
}
public static BigInteger Ackermann(BigInteger m, BigInteger n)
{
var stack = new OverflowlessStack<BigInteger>();
stack.Push(m);
while(!stack.IsEmpty)
{
m = stack.Pop();
skipStack:
if(m == 0)
n = n + 1;
else if(m == 1)
n = n + 2;
else if(m == 2)
n = n * 2 + 3;
else if(n == 0)
{
--m;
n = 1;
goto skipStack;
}
else
{
stack.Push(m - 1);
--n;
goto skipStack;
}
}
return n;
}
Again, calling Ackermann(4, 2) returns:
Which is the correct result. The stack structure used will never throw, so the only limit remaining is the heap (and time of course, with large enough inputs you'll have to use "universe lifetime" as a unit of measurement...).
Since the way it's used is analogous to the tape of a Turing machine, we're reminded of the thesis that any calculable function can be calculated on a Turing machine of sufficient size.
Use memoization. Something like:
private static Dictionary<int, int> a = new Dictionary<int, int>();
private static int Pack(int m, int n) {
return m * 1000 + n;
}
private static int Ackermann(int m, int n) {
int x;
if (!a.TryGetValue(Pack(m, n), out x)) {
if (m == 0) {
x = n + 1;
} else if (m > 0 && n == 0) {
x = Ackermann(m - 1, 1);
} else if (m > 0 && n > 0) {
x = Ackermann(m - 1, Ackermann(m, n - 1));
} else {
x = -1;
}
a[Pack(m, n)] = x;
}
return x;
}
However, this example only shows the concept, it will still not give the correct result for Ackermann(4, 2), as an int is way too small to hold the result. You would need an integer with 65536 bits instead of 32 for that.

Is there a method to find the max of 3 numbers in C#?

The method should work like Math.Max(), but take 3 or more int parameters.
You could use Enumerable.Max:
new [] { 1, 2, 3 }.Max();
Well, you can just call it twice:
int max3 = Math.Max(x, Math.Max(y, z));
If you find yourself doing this a lot, you could always write your own helper method... I would be happy enough seeing this in my code base once, but not regularly.
(Note that this is likely to be more efficient than Andrew's LINQ-based answer - but obviously the more elements you have the more appealing the LINQ approach is.)
EDIT: A "best of both worlds" approach might be to have a custom set of methods either way:
public static class MoreMath
{
// This method only exists for consistency, so you can *always* call
// MoreMath.Max instead of alternating between MoreMath.Max and Math.Max
// depending on your argument count.
public static int Max(int x, int y)
{
return Math.Max(x, y);
}
public static int Max(int x, int y, int z)
{
// Or inline it as x < y ? (y < z ? z : y) : (x < z ? z : x);
// Time it before micro-optimizing though!
return Math.Max(x, Math.Max(y, z));
}
public static int Max(int w, int x, int y, int z)
{
return Math.Max(w, Math.Max(x, Math.Max(y, z)));
}
public static int Max(params int[] values)
{
return Enumerable.Max(values);
}
}
That way you can write MoreMath.Max(1, 2, 3) or MoreMath.Max(1, 2, 3, 4) without the overhead of array creation, but still write MoreMath.Max(1, 2, 3, 4, 5, 6) for nice readable and consistent code when you don't mind the overhead.
I personally find that more readable than the explicit array creation of the LINQ approach.
Linq has a Max function.
If you have an IEnumerable<int> you can call this directly, but if you require these in separate parameters you could create a function like this:
using System.Linq;
...
static int Max(params int[] numbers)
{
return numbers.Max();
}
Then you could call it like this: max(1, 6, 2), it allows for an arbitrary number of parameters.
As generic
public static T Min<T>(params T[] values) {
return values.Min();
}
public static T Max<T>(params T[] values) {
return values.Max();
}
off topic but here is the formula for middle value.. just in case someone is looking for it
Math.Min(Math.Min(Math.Max(x,y), Math.Max(y,z)), Math.Max(x,z));
Let's assume that You have a List<int> intList = new List<int>{1,2,3} if You want to get a max value You could do
int maxValue = intList.Max();
Maximum element value in priceValues[] is maxPriceValues :
double[] priceValues = new double[3];
priceValues [0] = 1;
priceValues [1] = 2;
priceValues [2] = 3;
double maxPriceValues = priceValues.Max();
If, for whatever reason (e.g. Space Engineers API), System.array has no definition for Max nor do you have access to Enumerable, a solution for Max of n values is:
public int Max(int[] values) {
if(values.Length < 1) {
return 0;
}
if(values.Length < 2) {
return values[0];
}
if(values.Length < 3) {
return Math.Max(values[0], values[1]);
}
int runningMax = values[0];
for(int i=1; i<values.Length - 1; i++) {
runningMax = Math.Max(runningMax, values[i]);
}
return runningMax;
}
You could try this code:
private float GetBrightestColor(float r, float g, float b) {
if (r > g && r > b) {
return r;
} else if (g > r && g > b) {
return g;
} else if (b > r && b > g) {
return b;
}
}
This function takes an array of integers. (I completely understand #Jon Skeet's complaint about sending arrays.)
It's probably a bit overkill.
public static int GetMax(int[] array) // must be a array of ints
{
int current_greatest_value = array[0]; // initializes it
for (int i = 1; i <= array.Length; i++)
{
// compare current number against next number
if (i+1 <= array.Length-1) // prevent "index outside bounds of array" error below with array[i+1]
{
// array[i+1] exists
if (array[i] < array[i+1] || array[i] <= current_greatest_value)
{
// current val is less than next, and less than the current greatest val, so go to next iteration
continue;
}
} else
{
// array[i+1] doesn't exist, we are at the last element
if (array[i] > current_greatest_value)
{
// current iteration val is greater than current_greatest_value
current_greatest_value = array[i];
}
break; // next for loop i index will be invalid
}
// if it gets here, current val is greater than next, so for now assign that value to greatest_value
current_greatest_value = array[i];
}
return current_greatest_value;
}
Then call the function :
int highest_val = GetMax (new[] { 1,6,2,72727275,2323});
// highest_val = 72727275
You can use if and else if method for three values but it would be much easier if you call call twice Math.Max method like this
Console.WriteLine("Largest of three: " + Math.Max(num1, Math.Max(num2, num3)));
Console.WriteLine("Lowest of three: " + Math.Min(num1, Math.Min(num2, num3)));
If you don't want to repeatedly calling the Max function, can do like this
new List<int>() { A, B, C, D, X, Y, Z }.Max()
in case you need sorting as well:
var side = new double[] {5,3,4}
Array.Sort(side);
//side[2] is a maximum
as an another variant:
T[] GetMax<T>(int number, List<T> source, T minVal)
{
T[] results = new T[number];
for (int i = 0; i < number; i++)
{
results[i] = minVal;
}
var curMin = minVal;
foreach (var e in source)
{
int resComp = Comparer.DefaultInvariant.Compare(curMin, e);
if (resComp < 0)
{
int minIndex = Array.IndexOf(results, curMin);
results[minIndex] = e;
curMin = results.Min();
}
}
return results;
}
var source = new int[] { 5, 5, 1, 2, 4, 3 }.ToList();
var result = GetMax(3, source, int.MinValue);

Categories

Resources