这个MATLAB代码有什么问题?

时间:2012-10-21 23:05:43

标签: matlab concatenation dimensions

我正在尝试在MATLAB中进行以下操作,

global a b c d e f g h l;
A=[1 3;3 2];
B=[a 0;0 b];
C=[d 0;e f];
Ctranspose=transpose(C);
D=[sqrt(d) 0;0 sqrt(f)];
E=Ctranspose/D;
Etranspose=transpose(E);
K=A+E;
M=E*D*Etranspose;

for a=1:10
  for b=1:10
    if  K==M
      print(a);
      print(b);
      print(d);
      print(e);
      print(f);
    end
  end
end

我收到以下错误:

a)

Error using  + 
Matrix dimensions must agree.

Error in trial (line 6)
K=A+B

b)

Error using vertcat
CAT arguments dimensions are not consistent.

Error in trial (line 5)
C=[d 0;e f];

这里有什么问题?

(请注意,我是MATLAB的新手)

由于

4 个答案:

答案 0 :(得分:38)

哎哟!哎哟!让我直接跳到那里,在你继续沿着这条道路前打断你!

我知道你不是一个程序员,但在生活的某个阶段(显然,这是你的!),你必须面对事实并成为一个,无论如何。因此,要知道编程不是真正的科学,它是一门艺术,如果你愿意的话,是一种手艺,而且很容易出错。还要知道,在你面前有数以百万计的程序员,他们为你铺平了道路,发现哪种方法效果最好,哪种方法导致了某些灾难。

我将描述其中的六个"道路到某些厄运"代码中存在的内容。

列表上的

第一是使用global 不要使用全球变量!! 当然,它们适用于小而简单的东西,但更好,更易于管理,更耐用,更强大,传递数据的更容易出错的方法是手动。根据经验,创建所有顶级函数,尽可能少依赖其他函数/变量。这是因为全局变量在程序的状态和函数输出之间产生了紧密耦合,这使得重现任何错误(如果不是不可能的话)和调试(这实际上是任何程序员花费他的大部分时间) /她的时间)完整的噩梦。此外,除了正在运行的任何功能都可以更改它们,以便

function testMe
    global a;
    a = 5*rand;
    someFunction;
    b = 4*a; % ERROR! or...will it? 

function someFunction
    global a;
    a = a/5;
    if a < 0.5
        someOtherFunction; end

function someOtherFunction;
    global a;
    a = {'my string'};  

有时会工作,而有时会失败。可能发生更糟糕事情的一个例子:

function testMe
    global a, b;
    a = 5; b = 6;
    result = someCalculation;
    result = a*b*result;


function someFunction
    global a;
    a = sin(pi/rand); % INTENTIONAL

    % do LOTS of stuff here

    for a = 1:10 % OOPS! unintentional use of variable name
        % do stuff
        if (some weird condition)
            break; end
    end

没有错误,没有警告,没有,但你的结果仍然是垃圾。随着你的功能变得越来越大(通常也会这样),这个错误越来越难以找到和更难。花几天时间来发现这种错误并不罕见。

在您的代码中,您还可以更改循环内的全局变量ab。这意味着使用ab的任何函数/脚本(在完成后将被称为)将会显示a=10b=10。现在假设您在这些循环内调用函数,这会更改a的值。 a的值在a - 循环的下一次迭代中会是什么?假设你也得到了错误的结果。你会如何找到这个错误?

这样的代码通常被称为&#34;意大利面条代码&#34;,原因很明显。也许它会起作用,并且很容易编码,但最终它会让你大大减慢速度(更不用说继承你代码的人了)。

一种更好的方法可以阻止大部分容器,并且可以明确地传递它们。假设我们使用struct作为数据a-l

data = struct(...
    'a', a,...
    'b', b,...
    'c', c,...
    'd', d,...
    'e', e,...
    'f', f,...
    'g', g,...
    'h', h,...
    'l', l);

所以你可以说

result = myFunction(data);

访问myFunction中的数据如下所示:data.a获取a的值,或data.f获取f的值,等等。 data.k = 5; 中的myFunction不会更改 result,或者传递给函数的原始data - 您已经打破了紧密耦合并阻止了所有上述问题。

在Matlab命令窗口中键入help structhelp cell以了解这些类型的通用容器。

列表中的

第二使用变量名称l。这有些愚蠢,我可以简短地说:不要这样做:)与大多数人(甚至一些程序员)相信的相反,你一行代码只有一次,但是读取数百次,如果不是数千次。最佳做法是尽可能简化阅读,而不是编写l只是看起来像1,不是吗?错误k=1 vs k=lk=m vs k=1更难发现。

关键字

第三是关键字transpose。它有点冗长,不是吗?在数学中,你会使用A T ,这比在所有时间写完整定义要容易得多:

B = {A ij ➝A ji ∀i&lt; m⋏j&lt; Ñ

你通常只说B = A T 。在Matlab中也是如此。矩阵的transpose可以像这样完成:

Actrans = A' ; % conjugate transpose
Atrans  = A.'; % regular transpose

将您的代码减少到更简洁的

A = [1 3;3 2];
B = [a 0;0 b];
C = [d 0;e f];    
D = [sqrt(d) 0;0 sqrt(f)];
E = C.'/D;    
K = A+E;
M = E*D*E.';
列表中的

第四是等式K==M。就像它在这里一样,KM矩阵。表达式K==M被评估为元素,原因将在您的编程生涯后期变得明显:)这意味着K==M将再次成为矩阵,大小相同如KM,如果0K中的对应元素不相等,则包含M;如果这些元素相等,则1。那么,if - 语句会对这样的矩阵做什么呢?在Matlab中,只要第一个元素为真,它就是true(在我看来,它应该抛出错误,但是很好)。

这显然不是你想要的。我认为你想要的是两个矩阵中的所有元素是相等的。你最好使用它:

if all( abs(K(:)-M(:)) < eps )

其中(:) - 表示法意味着矩阵KM应在比较之前扩展为列向量。这是因为all()适用于单个维度,因此all(K==M) 仍然仍然是一个矩阵(实际上是矢量,但对于特殊情况,这是一个不同的名称)同一件事情)。请注意,我不使用相等(==),而是检查它们的差异是否小于某个微小值(eps)。这是因为在浮点运算(所有计算机都使用)中,乘法和平方根等运算通常会遇到舍入误差和近似/插值误差等问题。 平等是一个非常艰难的需求,在数学上讲的大多数情况下都难以评估true。您可以通过将二者的差异与一个与舍入误差(eps)相关的微小值进行比较来防止此失败检测到相等性。

列表中的

第五是您打印的方式。 print语句本身就会向系统的默认打印机发送一个数字,你知道,如果今天感觉像合作的话,那个用墨水喷出纸张的喜怒无常的机器:)现在,我假设您试图在屏幕上显示事物。这样做就像你开始展示事物的方式不是最好的方式:你会得到十几个未命名的非结构化值列表:

1     % which would be the value of 'a'
1     % which would be the value of 'b'
3     % which would be the value of 'd'
4     % which would be the value of 'e'
5     % which would be the value of 'f'
...

只看到出现的值会使阅读和解释所发生的事情变得相当繁琐。更好地使用更具描述性的内容:

if all( abs(K(:)-M(:)) < eps )

    % option 1
    a
    b
    d   % NOTE: not terminating with semicolon
    e
    f

    % option 2
    fprintf(...
        'a: %d\n, b: %d\n, d: %d\n, e: %d\n, f: %d\n\n', a,b,d,e,f); 

end

选项1将只显示

a = 
    1
b = 
    1
etc.

至少还会显示变量的名称及其值。选项2是更好的选择:

a: 1
b: 1
d: 3
e: 4
f: 5

a: 1
b: 2
d: 3
e: 4
f: 5

etc.

(另外,值a,b,d,e,f 永远不会在循环中更改,那么为什么要首先显示它们呢?)

列表中的

第六(和最后!)是特定于Matlab的一个:for - 循环。 Matlab是一种基于矩阵的解释语言。它的矩阵性质只意味着每个变量本质上都是一个矩阵。解释意味着您的代码不会被计算机的处理器直接看到,它必须在计算任何内容之前经过一系列的解释和翻译。这枚硬币有两面:

  • 它可以加快速度(比如编码,或执行&#34;琐碎的事情,如解决线性系统,FFT,矩阵比较等)。
  • 它可以减慢速度(比如重复执行语句,比如循环)

鉴于性能,for - 循环在Matlab中因为将操作带入爬行而臭名昭着。在Matlab中的方法通常是矢量化代码,例如,使用所有变量都是矩阵的事实,并对它们使用矩阵/张量运算而不是循环。这在大多数编程语言中并不是一种非常常见的方法(并且你会在不习惯它的程序员中看到很多强烈的,强烈的阻力),但在数学上下文中它很有意义。在求助于for循环之前,总是尝试使用矩阵/张量操作作为第一道攻击线(并且Matlab已经 很多 ,请注意!)。

所以, 你的代码有什么问题:)哦,是的,正如Andreas Hangauer已经提到过的那样,将陈述引用a通过{ {1}},以及所有需要在循环内重新计算的东西,你会没事的。

答案 1 :(得分:4)

您没有指定a b c d e f g h l的值是什么,您指定它们是全局变量。

a)第一个错误:鉴于第6行出现错误,ab不是标量。

b)第二个错误:(错误在第4行而不是第5行)。同样,def中的一个不是标量。这里发生的是de可能是标量,但f不是,f是向量或矩阵。因此矩阵的第一行具有与第二行不同的长度,因此出现错误。

for循环的意图是什么?仅当M==KM的所有元素相等时,K才会返回true,但第二行和第一列中的元素将永远不会相同。如果以某种方式MK是相同的矩阵,则代码只会打印def以用于{的所有值组合{1}}和a。 (请注意bab循环中重新定义。)

答案 2 :(得分:3)

您必须更改程序的顺序。

d = 4567; % some value necessary
e = 1234; % some value necessary
f = 4567; % some value necessary
for a=1:10
 for b=1:10

    A=[1 3;3 2];
    B=[a 0;0 b];
    C=[d 0;e f];
    Ctranspose=transpose(C);
    D=[sqrt(d) 0;0 sqrt(f)];
    E=Ctranspose/D;
    Etranspose=transpose(E);
    K=A+E;
    M=E*D*Etranspose;


   if  K==M
     print(a);
     print(b);
     print(d);
     print(e);
     print(f);

   end
 end
end

您似乎没有正确理解编程语言的基本概念。在编程语言中(与数学符号不同),语句是一个接一个地按顺序执行的命令。执行该命令时,计算中所需的所有值都必须可用,因此更新的执行顺序对于预期的操作是必需的。

答案 3 :(得分:2)

除了这里提到的所有内容之外,请很好地格式化代码(注意:下面的代码是OP的代码,因此编程错误):

global a b c d e f g h l;
A = [1 3; 3 2];
B = [a 0; 0 b];
C = [d 0; e f];
Ctranspose = transpose(C);
D = [sqrt(d) 0; 0 sqrt(f)];
E = Ctranspose / D;
Etranspose = transpose(E);
K = A + E;
M = E * D * Etranspose;

for a = 1:10
    for b = 1:10
        if  K == M
            print(a);
            print(b);
            print(d);
            print(e);
            print(f);
        end
    end
end

阅读代码时,这会节省您的时间和精力,实际上比需要更多的时间。