我正在尝试在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的新手)
由于
答案 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
没有错误,没有警告,没有,但你的结果仍然是垃圾。随着你的功能变得越来越大(通常也会这样),这个错误越来越难以找到和更难。花几天时间来发现这种错误并不罕见。
在您的代码中,您还可以更改循环内的全局变量a
和b
。这意味着使用a
和b
的任何函数/脚本(在完成后将被称为)将会显示a=10
和b=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 struct
或help cell
以了解这些类型的通用容器。
第二使用变量名称l
。这有些愚蠢,我可以简短地说:不要这样做:)与大多数人(甚至一些程序员)相信的相反,你写一行代码只有一次,但是读取数百次,如果不是数千次。最佳做法是尽可能简化阅读,而不是编写。 l
只是看起来像1
,不是吗?错误k=1
vs k=l
比k=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
。就像它在这里一样,K
和M
是矩阵。表达式K==M
被评估为元素,原因将在您的编程生涯后期变得明显:)这意味着K==M
将再次成为矩阵,大小相同如K
和M
,如果0
和K
中的对应元素不相等,则包含M
;如果这些元素相等,则1
。那么,if
- 语句会对这样的矩阵做什么呢?在Matlab中,只要第一个元素为真,它就是true
(在我看来,它应该抛出错误,但是很好)。
这显然不是你想要的。我认为你想要的是两个矩阵中的所有元素是相等的。你最好使用它:
if all( abs(K(:)-M(:)) < eps )
其中(:)
- 表示法意味着矩阵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
- 循环。 Matlab是一种基于矩阵的解释语言。它的矩阵性质只意味着每个变量本质上都是一个矩阵。解释意味着您的代码不会被计算机的处理器直接看到,它必须在计算任何内容之前经过一系列的解释和翻译。这枚硬币有两面:
鉴于性能,for
- 循环在Matlab中因为将操作带入爬行而臭名昭着。在Matlab中的方法通常是矢量化代码,例如,使用所有变量都是矩阵的事实,并对它们使用矩阵/张量运算而不是循环。这在大多数编程语言中并不是一种非常常见的方法(并且你会在不习惯它的程序员中看到很多强烈的,强烈的阻力),但在数学上下文中它很有意义。在求助于for循环之前,总是尝试使用矩阵/张量操作作为第一道攻击线(并且Matlab已经 很多 ,请注意!)。
所以, 你的代码有什么问题:)哦,是的,正如Andreas Hangauer已经提到过的那样,将陈述引用a
通过{ {1}},以及所有需要在循环内重新计算的东西,你会没事的。
答案 1 :(得分:4)
您没有指定a b c d e f g h l
的值是什么,您指定它们是全局变量。
a)第一个错误:鉴于第6行出现错误,a
或b
不是标量。
b)第二个错误:(错误在第4行而不是第5行)。同样,d
,e
或f
中的一个不是标量。这里发生的是d
和e
可能是标量,但f
不是,f是向量或矩阵。因此矩阵的第一行具有与第二行不同的长度,因此出现错误。
for
循环的意图是什么?仅当M==K
和M
的所有元素相等时,K
才会返回true,但第二行和第一列中的元素将永远不会相同。如果以某种方式M
和K
是相同的矩阵,则代码只会打印d
,e
和f
以用于{的所有值组合{1}}和a
。 (请注意b
和a
在b
循环中重新定义。)
答案 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
当阅读代码时,这会节省您的时间和精力,实际上比写需要更多的时间。