Могу ли я установить функцию Func <> с переменными времени выполнения, чтобы они не передавались в качестве параметров в C #? - PullRequest
1 голос
/ 24 декабря 2009

У меня есть программа численного анализа, которая для простоты вычисляет алгоритм, подобный следующему:

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

Я вычисляю значения a, b, c, d во время выполнения и хотел бы передать следующий эквивалент как Func<double, double>. Где я могу установить значение для X и получить Y.

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

Где 12,13,14,15 - числа, рассчитанные во время выполнения.

Я понимаю, что это можно сделать, передав двойной массив, например: Func<double[], double> но я стараюсь не пропускать константы (которых может быть много).

Есть ли способ установить эти числа в функции во время выполнения?

(желательно без вычисления a, b, c, d части самого Func <>? Расчет a, b, c, d составляет 80% работы)

например:.

a = ...

b = ...

c = ...

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

Для каждой оценки ABCD - я буду оценивать 10 х.

Ответы [ 5 ]

11 голосов
/ 24 декабря 2009

Я не уверен, что понимаю, что вы спрашиваете, но вы могли бы попробовать что-то подобное, возможно?

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

В этом случае вы можете просто позвонить на CreateCalculationFunc(), который будет выполнять тяжелые вычисления один раз, и вернуть многократно Func<double,double> для выполнения ваших переменных расчетов.

Конечно, это расширяется на любое количество предварительно вычисленных констант и более чем на одну переменную.

2 голосов
/ 24 декабря 2009

Звучит так, будто вы хотите, чтобы функциональные языки называли «карри» или «частичное применение».

Учитывая Func<a, b, c, d, x, result>, вы применяете значения одно за другим и уменьшаете набор параметров.

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

приведет к функции с подписью

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

, который вы можете передать.

Соответствующие ссылки для карри / частичного применения в C #:

Или - попробуйте F #;)

Редактировать: Образец краткого кода, созданный из ссылочных сайтов выше:

Код котельной:

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

Ваш код:

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 - теперь новый Func, который «знает» предварительно примененные значения и может быть передан как вам угодно. Я не смог найти готовое решение для делегатов с более чем 4 параметрами (т.е. вещи, которые не соответствуют Func <...>), но это также должно быть возможно.

Таким образом, вы рассчитываете один раз точно так же, как и сегодня, но вы можете сузить функцию до последней части для каждого потребителя.

2 голосов
/ 24 декабря 2009

Не можете ли вы создать класс, содержащий ваш метод вычисления (Func<double,double>), который имеет свойства для ваших "констант". Затем вы устанавливаете свойства и используете ссылку на метод Calculate в качестве вашего Func<double,double> делегата:

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;
    }
}
0 голосов
/ 28 декабря 2009

Оглядываясь назад, я мог бы просто сделать это;

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

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

    return Algorithm;
}

Но Func <> и Action <> меня немного смутили, так как я впервые их использовал! Спасибо за вашу помощь.

0 голосов
/ 24 декабря 2009

Существует несколько различных перегрузок Func <>, вы можете использовать одну с 5 универсальными параметрами , причем первым будет KeyValuePair :

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

Таким образом, вы передаете a и b как kvp, а c, d и x как другие параметры.

...