views:

124

answers:

5

Hello,

I have a numerical analysis program which for simplicity calculates an algorithm similar to:

y = ax^3 + bx^2 + cx + d;

I calculate the values of a,b,c,d at runtime and would like to pass the following equivalent as a Func<double, double>. Where I can set a value for X, and get Y.

y = 12x^3 + 13x^2 + 14x + 15;

Where 12,13,14,15 are the numbers calculated at runtime.

I realise this can be done by passing in a double array, like so: Func<double[], double> but I am trying to avoid passing around the constants (which can be many).

Is there any way to set these numbers in a func at runtime?

(Preferably without making the calculation of a,b,c,d part of the Func<> itself? The calculation of a,b,c,d is 80% of the work)

E.g.:

a = ...

b = ...

c = ...

Func<x, double> {
     ((const)a) * x^3 +   ((const)b) * x^2 +   ((const)c) * x + 15;
}`

For every evaluation of ABCD - I will evaluate 10 x's.

+1  A: 

Can't you create a class that contains your calculation (Func<double,double>) method that has properties for your "constants". Then you set the properties and use a reference to the Calculate method as your Func<double,double> delegate:

public class Calculator
{
    public double A { get; set; };
    public double B { get; set; };
    public double C { get; set; };
    public double D { get; set; };

    public double Calculate(double x)
    {
        return A*x*x*x + B*x*x + C*x + D;
    }
}
Joe
Thanks for your replies: There are a dozen numerical analysis techniques, I am finding the constants and then passing the Func<> as an argument to a global weighting method which will evaluate them all - for lots of values of X - and analyse the results.Possibly this would work? Set the values of abcd as a class instance. But this only works for ONE type of function, I would need a new class type for each numerical technique
JaredBroad
A: 

There are several different Func<> overloads, you can use one with 5 generic parameters, with the first one being a KeyValuePair:

Func<KeyValuePair<double,double>,double,double,double,double>

So you pass a and b as the kvp and c,d and x as the other parameters.

Oded
+7  A: 

I'm not sure if I understand quite what you are asking, but you could try something like this, perhaps?

Func<double, double> CreateCalculationFunc()
{
    double a = heavy calculation;
    double b = heavy calculation;
    double c = heavy calculation;
    double d = heavy calculation;

    Func<double, double> calculation = (x) =>
    {
        // You can use the constants in here without passing them as parameters
        return x * (a * b / c - d);
    };

    return calculation;
}

In this case, you can just make a call to the CreateCalculationFunc(), which will do the heavy calculations once, and return a reusable Func<double,double> for doing your variable calculations.

Of course, this is extensible to any amount of pre-calculated constants and more than one variable.

Alex
Is that works that is a great idea! Thanks =), I didn't think about nesting them.
JaredBroad
A: 

This sounds like you'd want what the functional languages call "currying" or "partial application".

Given a Func<a, b, c, d, x, result> you'd apply the values one by one and reduce the parameter set.

Func<a, b, c, d, x, result>(valueOfA)

would result in a function with the signature

Func<b, c, d, x, result>

which you can pass on.

Relevant links for currying/partial application in C#:

Or - give F# a try ;)

Edit: A short code sample, created from the reference sites above:

Boilerplate code:

    public static Func<B, R> Partial<A, B, R>(this Func<A, B, R> f, A a) {
  return b => f(a, b);
 }

 public static Func<B, C, R> Partial<A, B, C, R>(this Func<A, B, C, R> f, A a) {
  return (b, c) => f(a, b, c);
 }

 public static Func<B, C, D, R> Partial<A, B, C, D, R>(this Func<A, B, C, D, R> f, A a) {
  return (b, c, d) => f(a, b, c, d);
 }

Your Code:

Func<double, double, double, double, double> yourCalculation = (a, b, c, x) => a*Math.Pow(x, 3) + b*Math.Pow(x, 2) + c*x;

var aDefined = yourCalculation.Partial(12);
var bDefined = aDefined.Partial(13);
var cDefined = bDefined.Partial(14);

cDefined is now a new Func that "knows" the preapplied values and can be passed around as you like. I couldn't find a readymade solution for delegates with more than 4 parameters (i.e. things that don't fit a Func<...>), but that should be possible as well.

This way you're precalculating once and just the way you do it today, but you can narrow down the function to the last part for every consumer.

Benjamin Podszun
A: 

In hindsight I could actually just do this;

Class {
    a = ...
    b = ...

    Func Algorithm = (x) => {
        return x*a + x*b;
    }

    return Algorithm;
}

But was just a little confused by Func<> and Action<> as it was my first time using them! Thanks for your help.

JaredBroad
That code makes no sense... Class is what? A method? Because it has a return statement in it. And if that is the case, it's the same as my answer. :-P
Alex