一般分配律(general distributive law):
其中J与K为任意实数集,一般分配律可用交换求和次序(interchanging the order of summation)证明。
一般分配律有两种基本类型:
简易型(vanilla):
以及复杂型(rocky road):
艾弗森方程(Iverson Equation):
[1<=j<=n][j<=k<=n]=[1<=j<=k<=n]=[1<=k<=n][1<=j<=k]
该方程应用于复杂型的一般分配律可以得到:
假设ai(i为1-n),和bj(j为1-m),求所有ai*bj之和(对于任意i,j在其已给出范围内),用一般的方法,需要先计算m*n次乘法,再计算m*n-1次加法,设机器计算一次的加法的平均时间为T,计算一次乘法的为R(R远大于T),则一般方法需要的总时间Time1=m*n*R+(m*n-1)*T=m*n(T+R)-T
而应用一般分配律,则先分别计算(n-1)和(m-1)次加法,再计算1次乘法,就可以得出结果,需要的总时间Time2=R+(m+n-2)*T
可以估算出第一个的总时间大概是第二个的n倍左右,计算的时间大大减少。
编程实现:
已知数列an和二维矩阵:
即A(j,k)=aj*ak,求对角线及其以上所有元素之和,即:
根据该矩阵的定义可知,对角线及其以上所有元素之和和对角线及其以下上所有元素之和相等,所以
即对角线及其以上所有元素之和和对角线及其以下所有元素之和之和等于矩阵中所有元素之和加对角线上所有元素之和。根据一般分配律,可化为:
则
编程实现代码:
#include <iostream>
#include <stdlib.h>
#include <sys/time.h>
#define n 10000
using namespace std;
void cal1(int a[]){
long long int s=0;
struct timeval startTime, stopTime;
gettimeofday(&startTime, NULL);
for(int i=0;i<n;i++){
for(int j=0;j<=i;j++){
s+=a[i]*a[j];
}
}
gettimeofday(&stopTime, NULL);
long elapsed = (stopTime.tv_sec-startTime.tv_sec) * 1000000 + (stopTime.tv_usec - startTime.tv_usec);
cout<<"answer:"<<s<<" runtime:"<<elapsed<<endl;
}
void cal2(int a[]){
long long int s=0;
long long int q1=0,q2=0;//q1 an的和 q2 an方的和
time_t start,end;
struct timeval startTime, stopTime;
gettimeofday(&startTime, NULL);
for(int i=0;i<n;i++){
q1+=a[i];
q2+=a[i]*a[i];
}
s=0.5*(q1*q1+q2);
gettimeofday(&stopTime, NULL);
long elapsed = (stopTime.tv_sec-startTime.tv_sec) * 1000000 + (stopTime.tv_usec - startTime.tv_usec);
cout<<"answer:"<<s<<" runtime:"<<elapsed<<endl;
}
int main(){
int a[n];
// srand((unsigned)time( NULL ));
for(int i=0;i<n;i++){
a[i]=rand();//其实为伪随机数,具体设随机数方法不列
}
cal1(a);//普通方法
cal2(a);//新方法
}
运行结果: