3

我正在编写一些 matlab 代码并编写了一个有效的算法,但我认为它不是特别有效。由于我正在努力提高我的编程技能,我想知道是否有更有效的方法来做到这一点。

我有一个(相当大的~E07)值矩阵,这些值是无序的,但在 [-100, 100] 范围内。我想使用以下规则在第一个矩阵的基础上创建第二个矩阵:

  1. 如果该点的值 > 70,则该点的值应设置为 70。
  2. 如果该点的值 < -70,则该点的值应设置为 -70。
  3. 所有其他值应四舍五入到最接近的 5 倍数。

这是我目前正在做的事情:

data = 100*(-1+2*rand(1,10000000)); % create random dataset for stackoverflow
new_data = zeros(1,length(data));

for i = 1:length(data)
    if (data(i) > 70)
        new_data(i) = 70;
    elseif (data(i) < -70)
        new_data(i) = -70;
    else
        new_data(i) = round(data(i)/5.0)*5.0;
    end
end

有没有更有效的方法?我认为应该有一种方法可以使用逻辑索引来做到这一点,但这些对我来说是一个新发现......

4

3 回答 3

8

您根本不需要循环:

data = 100*(-1+2*rand(1,10000000)); % create random dataset for stackoverflow
new_data = zeros(1,length(data)); % note that this memory allocation is not necessary at this point

new_data = round(data/5.0)*5.0;
new_data(data>70) = 70;    
new_data(data<-70) = -70;
于 2012-10-11T13:37:33.397 回答
5

更容易的是使用最大值和最小值。用简单的一行来完成。

new_data = round(5*max(-70,min(70,data)))/5;
于 2012-10-11T14:27:37.233 回答
2

H.Muster 和 woodchips 的两个答案当然是这样做的方法,但仍有一些小的改进有待发现。如果你追求性能,你可能想利用你的问题的细节。例如,您的输出数据是 integers -100 <= x <= 100。这显然适用于 8 位有符号整数数据类型。此代码(注意int8从任意双精度数据显式转换)

% your double precision input data
data = 100*(-1+2*rand(1,10000000));

% cast to int8 - matlab does usual round here
data = int8(data);
new_data = 5*(max(-70,min(70,data))/5);

最快有两个原因:

  • 1 个数据元素占用 1 个字节,而不是 8 个字节。内存带宽是这里的一个限制因素,所以你会得到很多改进
  • 不再需要回合

以下是 H.Muster、woodchips 和我的小修改的代码中的一些时间:

H.Muster    Elapsed time is 0.235885 seconds.
woodchips   Elapsed time is 0.167659 seconds.
my code     Elapsed time is 0.023061 seconds.

差异是相当惊人的。尽管 MATLAB 在任何地方都使用双精度,但您应该尽可能尝试使用整数数据类型。

编辑这是因为 matlab 如何实现整数运算。与 C 中不同的是,将 double 转换为 int 意味着一个round操作:

a = 0.1;
int8(a)

ans =
  0

a = 0.9;
int8(a)

ans =
  1
于 2012-10-11T16:36:26.873 回答