简体   繁体   中英

Recursive Function to calculate factorial using PLINQ

NOTE I am well aware of what I am asking, and there is no way I would need the use of a function such as this on a normal basis, but it is being used as a research factor for a graduate project on factorial experiments I am conducting.

I have the following function in which I want to run using PLINQ (Not TPL). I know that PLINQ runs on top of TPL, but this part of the experiment. Additionally, unless I am unaware of another way to do it with PLINQ, I believe I will have to somewhat "hack" the factorial method to use a for loop with recursion.

Since the Parallel class only offers For,ForEach and Invoke, it doesnt offer what I need, such as what the TPL does, I need it to return, and Invoke doesnt do that, so I will have to use For and do a for loop from 0,1 for each recursive call (yes, I know it seems rediculous).

I want to do something like the following:

public ulong RecursivePLINQ(ulong factor)
    {
        if (factor > 1)
        {
            Parallel.For<ulong>(0, 1, () => factor, (j, loop, factorial) =>
            {
                Thread.Sleep(1);    /*Simulate Moderate Operation*/
                return factorial * RecursivePLINQ(--factorial);
            }, (i) => { });
        }


        return 1;

    }

Currently, what is happening is it seems to be working, but on the final call its returning 1, and the result of the recursive call is 1, and not the recursive changed value. I can't seem to come across what is wrong. I have the alternate TPL implementation (again for research) shown here, which is working.

public ulong RecursiveTPL(ulong factor)
    {
        if (factor > 1)
        {
            Task<ulong> task = new Task<ulong>((f) =>
            {
                Thread.Sleep(1);    /*Simulate Moderate Operation*/
                ulong val = (ulong)f;
                return factor * RecursiveTPL(--val);
            }, factor);
            task.Start();
            task.Wait();
            return task.Result;
        }
            return 1;


    }

*** AGAIN PLEASE DO NOT FLAME ME FOR WHAT I AM ASKING, IT IS FOR A VERY SPECIFIC RESEARCH PURPOSE * ****

EDIT I saw an example on MSDN docs that showed the use of thread local variables so I tried something like this, but my head is starting to spin a little bit...Dont pay attention to the casting, its only to see if I can get it to work...

public ulong RecursivePLINQ(ulong factor)
    {
        long total = 0;
        if (factor > 1)
        {
            Parallel.For<ulong>(0, 1, () => factor, (j, loop, factorial) =>
            {
                Thread.Sleep(1);    /*Simulate Moderate Operation*/
                return factorial * RecursivePLINQ(--factorial);
            }, (i) =>  Interlocked.Add(ref total,(long)i)
            );
        }


        return (ulong)total;

    }

Its not pretty, and I am really not sure if this is even valid for my purpose, but it does give me the correct factorial. I got this solution, but I have to do this correting of the total parameter to get it to work, not sure what I would call that, or if there is a better way to do it, but this will have to do for now...

public long RecursivePLINQ(long factor,long total)
    {

        if(total == 0)
        {
            total = 1;
        }
        if (factor > 1)
        {
            Parallel.For<long>(0, 1, () => factor, (j, loop, factorial) =>
            {
                Thread.Sleep(1);    /*Simulate Moderate Operation*/
                total = factorial * RecursivePLINQ(--factorial, total);
                return total;
            }, (i) =>  {return;});
        }
        return total;
    }

Shamelessly copying from this Dr Dobbs article , you can use the Aggregate extension method to calculate the factorial:

int value=5; 
var factorial=Enumerable.Range(1, value).AsParallel()
             .Aggregate(1, (result, number)=>      
                           result*number, result=>result);

You can argue that Aggregate performs the recursion you would do by hand, or you could write code that recursively calls itself to calculate the factorial.

Like everyone else, though, I fail to see what you will accomplish. Your code will be dominated by the setup and teardown of PLINQ and whatever numbers you get will be meaningless.

If anything, PLINQ is used to REPLACE recurrent code with a sequence of operators that can be executed in parallel without the programmer having to specify how this will happen.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM