【问题标题】:For loop taking a long timeFor循环需要很长时间
【发布时间】:2016-08-30 06:29:20
【问题描述】:

我正在模拟 1,000,000 个重复的 Irwin Hall 分布,每个重复是 100 个均匀随机变量的总和。我创建了这个程序,我认为它是正确的,但是 MATLAB 已经运行了一整夜并且没有完成,所以(显然)出了点问题,但我看不到在哪里。这是我的程序,希望有人能看到这个问题。

n=100; % Nb of samples
N=1000000; %Nb of replicates

for jj=1:N
    for ii=1:n
        x(ii)=rand();
    end
    s(jj)=sum(x);
    mu=mean(s);
    sigma2=var(s);
    sigma=std(s);
    S(jj)=1-normcdf((70-mu)/sigma);
    if mod(jj, 100000)==0
        jj
    end
end

histogram(S) 

【问题讨论】:

  • 你部门/s igma的空间真的存在吗?另外,为什么不只是x = rand(100,1);
  • 一百万次迭代将需要很多时间!!还可以考虑pre-allocating 用于xsS 的内存以节省一些时间!
  • /s igma 已更正,但问题仍然存在 :(
  • @Orongo 为什么将我的代码复制到问题本身,却对 Dohyun 的回答发表了评论?请不要复制我的代码,而是在 cmets on my answer 中解释不清楚的地方(因为这是您从那里获得此代码的地方)。我将回滚您所做的编辑,因为我和 Dohyun 的回答对当前问题都没有意义。

标签: performance matlab for-loop


【解决方案1】:
n=1e2; % Nb of samples
N=1e6; % Nb of replicates
s = zeros(1,N); % INITIALISE, INITIALISE, INITIALISE
S = zeros(1,N); % INITIALISE, INITIALISE, INITIALISE

for jj=1:N
    x=rand(n,1); % Remove redundant inner loop
    s(1,jj)=sum(x);
    tmp = s(1,1:jj); % Create temporary storage for convenience
    mu=mean(tmp);
    sigma=std(sigma2); % You don't need the variance at all
    S(1,jj)=1-normcdf((70-mu)/sigma);
     if mod(jj, 1e5)==0
         disp('We are at iteration %i',jj); % Proper display command
     end
end

histogram(S) 

这段代码在我的 i5-750 处理器上使用 N=1e4 在半秒内运行。

最重要的是:不要打印到像 jj 这样的控制台。要么根本不打印,要么使用disp 命令来清楚起见。打印到控制台需要很长时间。还有initialise your variables。在循环中增长变量需要很长时间。每次增加变量的长度,这里一百万次,你强制MATLAB首先创建一个初始长度+1的变量,然后复制内容,然后删除旧变量。这可能是您的代码花费这么长时间的原因。

我还使用了一个临时变量 tmp 来使您的代码中的转换稍微容易一些。

【讨论】:

  • 速度不错!不过,那个显示看起来很可疑。 -- 原则上,我会根据 var 计算 std(而不是再次根据数据)。
  • @DennisJaheruddin 原始代码中有唯一的jj 让我感到相当惊讶。我怀疑他想要某种进度表,所以我给他打电话给disp
  • 我明白你为什么要这样做,但是这个调用似乎不起作用。
  • @DennisJaheruddin 呵呵,是的,我忘了转义单引号。省略了 are 的缩写并以这种方式修复它。不错的收获
【解决方案2】:

我预先分配了变量S 并对部分代码进行了矢量化处理。

tic;

n=100; % Nb of samples
N=1000000; %Nb of replicates

x = rand(n,N); % x(ii) = rand();
s = sum(x); % s = sum(x);
mu = cumsum(s)./(1:N); % mu = mean(s);

S = zeros(N,1);
for jj=1:N
    sigma=std(s(1:jj));
    S(jj)=1-normcdf((70-mu(jj))/sigma);
    if ~mod(jj,100000)
        fprintf('%d %.2f\n',jj,toc);
    end
end

toc

histogram(S)  

我明白了

N        orginal  modified
----------------------------
1e+05     54.07      31.9
2e+05    246.37     173.6
3e+05    621.06    450.91
4e+05    1161.2    835.03
5e+05    1837.5    1329.4
6e+05    2661.4    1930.3

配备 i5-6200U 处理器和 8GB DDR3 RAM。

由于随着jj 的增大,计算变得越来越重,如果您运行N = 10^6 的代码,将需要相当长的时间。

由于您没有预先分配变量,因此当您将N 设置得更大时,差异会更大。

尽管 MATLAB 可以处理可变大小的修改,但 MATLAB高度 建议您预先分配内存。每次 MATLAB 到达变量的边界时,MATLAB 都会尝试重新分配内存,这需要更多时间。即使你无法计算出准确的内存大小,也最好预先分配一些粗略猜测的变量,然后在循环后擦除未使用的部分。

【讨论】:

  • 知道这一点真的很好,而且会派上用场。运行耗时 6 小时,结果和代码现在在问题行中。我对结果感到有些震惊,因为这是一个学习练习,我对结果和运行时间感到惊讶,因为它们都非常普通。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-21
  • 2019-02-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多