3

我正在尝试在 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

我收到以下错误:

一个)

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

4 回答 4

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循环内部。这意味着任何使用aand的函数/脚本,在这个完成后被b调用,都会看到and 。现在假设你这些循环中调用了一个函数,它改变了. -loop的下一次迭代的值是多少?假设你也得到错误的结果。您将如何发现该错误?a=10b=10aaa

出于显而易见的原因,这样的代码通常被称为“意大利面条代码”。也许它会起作用,并且易于编码,但最终它总是会大大减慢您的速度(更不用说继承您的代码的人了)。

防止大部分情况发生的更好方法是在更大的容器中收集数据,并明确地传递它们。假设我们使用 astruct作为数据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获取 的值adata.f的值f等。说data.k = 5;inmyFunction 不会改变,result或传递给函数的原始data值 - 您已经打破了紧密耦合并防止了所有上述问题。

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

列表中的第二个是使用变量 name l。这有点傻,我可以简短地说:不要那样做:) 与大多数人(甚至一些程序员)所相信的相反,你只了一行代码,但你了数百甚至数千次。最好的做法是让阅读尽可能简单,而不是写作l只是看起来像,1不是吗?错误k=1vs比vsk=l更难发现。k=mk=1

名单上的第三个transpose是关键字。这有点冗长,不是吗?在数学中,您将使用 A T,这比一直写完整定义更容易理解:

B = { A ij ➝ A ji ∀ i < m ⋏ j < n

你通常只是说 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。因为它在这里,K并且M矩阵。表达式K==M按元素计算的,原因在你以后的编程生涯中会变得很明显:) 这意味着这K==M将再次是一个矩阵,大小与Kand相同M,包含如果和中的0对应元素不相等,以及如果这些元素是平等的。那么,-statement 将如何处理这样的矩阵呢?在 Matlab 中,只要第一个元素为真(在我看来,它应该抛出一个错误,但是哦,好吧)。KM1iftrue

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

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

其中(:)-notation 表示矩阵K并且M应该在比较之前扩展为列向量。这是因为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-loops。Matlab 是一种解释型、基于矩阵的语言。它的矩阵性质只是意味着每个变量本质上都是一个矩阵。解释意味着您的代码不会直接被计算机的处理器看到,它必须经过一系列解释和翻译才能计算出任何东西。这枚硬币有两个面:

  • 它可以加快速度(比如编码,或者做一些“琐碎”的事情,比如求解线性系统、FFT、矩阵比较等)
  • 它可以减慢速度(比如重复执行语句,比如在循环中)

考虑到性能,for-loop 在 Matlab 中因使操作变得爬行而臭名昭著。在 Matlab 中采用的方法通常是矢量化代码,例如,使用所有变量都是矩阵的事实,并对其使用矩阵/张量运算而不是循环。在大多数编程语言中,这不是一种非常常见的方法(在不习惯它的程序员中,你会看到很多强烈的、激烈的抵制),但在数学环境中,它很有意义。在诉诸 for 循环之前,始终尝试使用矩阵/张量运算作为第一道攻击线(Matlab 有很多,请注意!)。

所以,就是你的代码的问题:) 哦,是的,正如 Andreas Hangauer 已经提到的,将引用athrough的语句l以及所有需要重新计算的语句放在循环中,你会没事的。

于 2012-10-22T07:04:01.543 回答
4

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

a) 第一个错误:假设第 6 行出现错误,它要么是标量,a要么b不是标量。

b) 第二个错误:(错误在第 4 行而不是第 5 行)。这里又是一个d, eorf不是一个标量。这里发生的是,d可能e是标量,但f不是,f 是向量或矩阵。因此矩阵的第一行与第二行的长度不同,因此存在误差。

for循环的目的是什么?仅当和的M==K所有元素都相等时才会返回 true ,但第二行和第一列中的元素永远不会相同。如果不知何故和是相同的矩阵,那么代码将只打印,和的所有值组合。(注意和在循环中重新定义。)MKMKdefababfor

于 2012-10-21T23:29:12.793 回答
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

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

于 2012-10-21T23:35:06.297 回答
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

这可以节省您阅读代码时的时间和精神资源,这实际上比编写代码要花费更多的时间。

于 2012-10-22T14:26:35.287 回答