变量乘法的优化

时间:2010-09-20 14:03:36

标签: c algorithm optimization math matrix

[这最初是在矩阵上,但我想它一般适用于任何变量]

假设我们有Var1 * Var2 * Var3 * Var4

其中一个零星地改变,其中一个是随机的。

是否可以最小化乘法?

如果我这样做

In case Var1 changes: newVar1 * savedVar2Var3Var4

我注意到,每当Var2,Var3,Var4改变时,我需要重新计算savedVar2Var3Var4。

重新计算'已保存的组合'是否会违背目的?

8 个答案:

答案 0 :(得分:7)

如果你有更多的数字要乘,或者乘法非常昂贵,那么有一件事我可以想到。

如果你有大量的数字要加倍,那么你可以将它们分成子集并记住每组的产品。当某个特定集发生更改时,由于其中一个成员发生更改,则备忘产品将变为无效并需要重新计算。您可以在多个级别执行此操作,具体取决于乘法的成本,可用的内存量以及更改的频率。如何在C中最好地实现这一点可能取决于变量如何变化 - 如果一个事件出现“这里是C的新值”,那么你可以使所有产品中包含C的产品无效(或检查旧的C实际上与失效前的新C不同)。如果它们是易变变量,那么您可能只需要将每个当前值与先前的值进行比较(这可能需要花费多少时间,只需将任何机器与硬件乘法指令相乘)。

所以,如果你有:

answer = A * B * C * D * E * F * G * H;

那么你可以把它们分开来:

answer = ( (A * B) * (C * D) ) * ( (E * F) * (G * H) );

然后,如果不是直接在C中完成这个乘法,那么你应该在表达式树上进行:

                         answer
                            *
                           / \
                          /   \
                         /     \
                     ABCD       EFGH
                     *             *
                    / \           / \
                   /   \         /   \
                 AB    CD       EF    GH
                 *      *       *      *
                / \    / \     / \    / \
               A   B  C   D   E   F  G   H

然后在每个级别(也许只是前几个级别)你可以有一个memoized子答案以及一些数据来告诉你它下面的变量是否已经改变。如果事件进来告诉您更改变量,则可能导致表达式失效在收到事件时向上传播(或者只是重新计算每个事件的记忆子答案)。如果变量只是神奇地改变而你必须检查它们以告诉它们确实发生了变化,那么你还有更多工作要做。

哦,另一种做到这一点的方法就是突然出现在我脑海里,我很惭愧,我没想到它。如果您确实知道已更改的变量的旧值和新值,只要旧值不为0,您就可以:

new_answer =  (old_answer * new_var) / old_var;

在实际数学中这可行,但在计算机数学中,这可能会失去太多精确度。

答案 1 :(得分:5)

首先,像这样的微观优化几乎是不值得的。花时间查看是否存在性能问题,查看问题所在的配置文件,并在进行更改后进行测试,看看您是否做得更好或更糟。

第二,数字的乘法在现代CPU中通常很快,而分支可能更贵。

第三,您的设置方式,如果Var1发生变化,您需要重新计算savedVar1Var2Var3saved Var1Var2Var4saved Var1Var3Var4和整个产品。显然,你最好只重新计算总数。

答案 2 :(得分:4)

是的,这是可能的。

对于标量,可能没有任何好处。对于较大的矩阵数学,您可以计算和存储:Var1 * Var2和Var3 * Var4。你的结果就是这两件事的结果。现在当一个更改时,您只需要更新2个产品而不是3个。只更新2个存储产品中的一个,具体取决于谁更改,并更新结果。

你有它,每次更新时有2次乘法而不是3次。这只会让你受益,如果常见的情况只是其中一个更新,但如果这是真的,它应该有很多帮助。

答案 3 :(得分:3)

我认为你不会节省任何时间。每当N个变量中的一个发生变化时,你需要计算(N - 1)个附加产品,对吧?假设您有A,B,C和D.更改,并保存了B,C和D的产品,但现在您必须重新计算缓存的ABC,ABD和ACD产品。事实上,你正在做更多的工作。 A B C D是三次乘法运算,而A BCD,A B C,A C D,以及 B D适用于SEVEN。

答案 4 :(得分:3)

答案取决于价值变化的频率。在您的示例中,计算savedVar2Var3Var4会花费您两次乘法,每次Var1更改时会增加一次(或者您需要计算总数)。那么:与Var1相比,Var2,Var3,Var4改变了多少次?

如果Var1的变化频率超过其他变量的3倍,则应该根据需要重新计算savedVar2Var3Var4。

答案 5 :(得分:2)

我不认为增益是值得的,除非你的“乘法”操作涉及繁重的计算(矩阵?)。

编辑:我添加了一个显示你的例子......它不值得:)

T multiply(T v1, T v2, T v3, T v4)
{
    static T v1xv2 = v1*v2;
    static T v1xv3 = v1*v3;
    static T v1xv4 = v1*v4;
    static T v2xv3 = v2*v3;
    static T v2xv4 = v2*v4;
    static T v3xv4 = v3*v4;

    static T v1save = v1;
    static T v2save = v2;
    static T v3save = v3;
    static T v4save = v4;

    if v1save != v1 
    {
        v1save = v1;
        v1xv2 = v1*v2;
        v1xv3 = v1*v3;
        v1xv4 = v1*v4;
    }

    if v2save != v2
    {
        v2save = v2;
        v1xv2 = v1*v2;
        v2xv3 = v2*v3;
        v2xv4 = v2*v4;
    }


    if v3save != v3
    {
        v3save = v3;
        v1xv3 = v1*v3;
        v2xv3 = v2*v3;
        v3xv4 = v3*v4;
    }

    if v4save != v4
    {
        v4save = v4;
        v1xv4 = v1*v4;
        v2xv4 = v2*v4;
        v3xv4 = v3*v4;
    }

    return v1xv2*v3xv4;

}

答案 6 :(得分:1)

假设您有许多变量的总和,例如Sum = A+B+C+D+....,其中一个变更,如C。如果C'C的旧值,那么您可以说Sum += (C-C');

产品的相同想法:Product *= C/C';。 (对于矩阵,它们必须是可逆的。)

当然,你可能会遇到爬行错误,所以偶尔你可以重新计算整个事情。

答案 7 :(得分:0)

我会尝试这样的事情:

var12 = var1*var2;
var34 = var3*var4;
result = var12*var34;
while (values available) {
        get new values;
        if (var1 changes || var2 changes) var12 = var1*var2;
        if (var3 changes || var4 changes) var34 = var3*var4;
        result = var12*var34;
}

没有过载(只有变更检查),它可以用于矩阵(不依赖于交换性,只依赖于相关性)。