(我会回答,尽管这是家庭作业。我认为很多人不理解为什么创建 bsxfun。)
乘法还有其他解决方案。典型的方法是使用 repmat、使用循环或乘以对角矩阵。如果将对角矩阵设为稀疏矩阵,则更好。但是,bsxfun 绝对是正确的解决方案。它是为解决此类问题而编写的。问题是当你做类似的事情时
A = magic(3) + 5
MATLAB 知道它必须将 5 加到 magic(3) 的每个元素上。同样,当你这样做时
A = magic(4).*2
同样,MATLAB 理解乘法将扩展到所有元素。实质上,MATLAB 在加法或乘法中将标量隐式扩展为与其伙伴大小相同的数组,然后执行运算。这是 repmat 求解器明确完成的。
显式标量扩展的问题在于,进行该扩展需要时间和内存。所以 times 和 plus 足够聪明,可以识别出标量扩展是合适的,但实际上并没有执行显式的内存占用操作。当您尝试时,MATLAB 不知道该怎么做
A = magic(3).*rand(1,3)
过去,解决方案是使用 repmat。但是,当您使用 repmat 将向量显式扩展为矩阵时,您会占用大量内存来以向量化方式解决问题。是的,向量化在 MATLAB 中用内存换取时间是很常见的,但如果您的内存已经有限,并且您正在处理一个大问题,这可能是一件坏事。在没有必要的情况下,强制 MATLAB(和您的操作系统)移入虚拟内存是一个非常糟糕的主意。 (对于一个小问题,任何解决方案都是可以接受的。)
因此,当您尝试将诸如 magic(3) 之类的数组乘以行向量或列向量时,MATLAB 是否应该理解它应该将向量隐式扩展为数组?或者 MATLAB 是否应该假设您犯了一个错误,并将其标记为这样?这个被称为单例维度扩展的问题就是问题所在。 (在向量中找到一个单一维度,其中一个维度是 1。)返回错误消息对许多用户来说是一个好主意,因为这通常表明发现了一个错误,一个错误。简单、自动地扩展所有单件维度以适应手头的问题似乎很危险。事实上,有很多关于如何做的讨论。例如,MATLAB 是否应该创建一个首选项,用户可以在其 MATLAB 版本中启用单例维度的扩展?这将是一个糟糕的主意,因为它会使代码无法跨系统移植。
此外,如果将基本 MATLAB 运算符修改为始终扩展所有单例维度,则 MATLAB 代码将无法移植回旧版本。
我们甚至讨论过创建一组全新的 MATLAB 运算符,例如 .* 与 * 并行存在,以便在扩展单例维度的同时进行运算。这也是一个糟糕的主意,应该避免。
解决方案是创建 BSXFUN(二进制标量扩展函数),以便在需要时有效地完成此操作。在文件交换中发现了一个 bsxfun,它允许旧版本的用户获得这种行为,因此尽可能地保持可移植性。 BSXFUN 允许您对任何一对参数进行操作,在它们之间应用用户提供的函数。所以它允许你做这样的事情:
A = rand(5,1);
B = rand(1,3);
C = bsxfun(@plus,A,B);
创建一个由A和B中元素之和组成的5x3矩阵。您也可以使用任何函数作为第一个操作数,因此BSXFUN非常强大。
最后,另一种看待 BSXFUN 的方式是作为外部产品的变体。因此,MATLAB 中的这个操作是完美定义的:
A = rand(5,1);
B = rand(1,3);
C = A*B;
但是,这些操作中的任何一个
D = A-B;
E = A^B;
会产生错误。 BSXFUN 允许您高效地完成它们,而不会占用内存的单例维度扩展。
D = bsxfun(@minus,A,B);
E = bsxfun(@power,A,B);