一个单精度矩阵乘法的问题

10视图(30天)
剑
2023年5月18日
编辑: 詹姆斯Tursa 2023年5月25日
脚本:
= (-0.1708981,-0.1415759,-0.0727073,-0.0554292;
0.0000000,-0.1715775,-0.1147511,-0.1098115;
0.0000000,0.0000000,-0.4013846,-0.3982548;
0.0000000,0.0000000,0.0000000,-0.0430463);
一个=单(a);
b = (16557086; 16557086; 3241423; 3241423);
b =单(b);
y = a * b;
z = 0 (4,1);
z =单(z);
2 = 1:1:4
jj = 1:1:4
z (ii) = a (ii, jj) * (jj) + z (ii);
结束
结束
c = - z;
情节(c)% = >它并不都是0
算法说y和z应该是相同的,但c并不都是0,这是为什么呢?
甚至个别行和列相乘的区别。
9日评论
詹姆斯Tursa
詹姆斯Tursa 2023年5月19日
编辑:詹姆斯Tursa 2023年5月19日
“…有可能mtimes作品不同(计算)在不同硬件?……”
是的。函数mtimes()在后台执行完整的双矩阵和单由多线程布拉斯特区图书馆。随时,图书馆改变你应该期望的输出可能会有小的差异。不同的MATLAB版本可能使用不同的库,不同的机器/硬件可能使用不同的库或调用不同的例程的库(例如,对称的、通用的),或者使用相同的库但有不同数量的线程可用。所有这一切会影响计算的顺序。MATLAB用于获取巴拉斯& LAPACK从第三方库。我最近没检查,但我相信他们仍然做的。底线是你不应该指望浮点计算比较不同的MATLAB环境时一定完全匹配。

登录置评。

接受的答案

约翰D 'Errico
约翰D 'Errico 2023年5月18日
编辑:约翰D 'Errico 2023年5月18日
你为什么困惑?从不相信一个浮点数的最低有效位。
这些数字是单身。所以最低有效位的大小
每股收益(“单一”)
ans =1.1921 e-07
现在你加减,乘以1 e7的数字。你意识到当MATLAB计算写道,没有假设,将加减在完全相同的序列的显式循环你写了吗?这意味着,从不相信的最低有效位浮点结果。
不同的是现在的1,实际上,0.25。一个惊喜!不是。
浮点运算不是正确准确的数学运算。事实上,它只是一个近似精确数学上正确的算法。在大多数情况下很好的近似。(适合单身略低于双打,但在这方面的差异是无关紧要的。)作为一个近似,总有小错误。然后当你放大这些错误,你可以找到他们,如果你看起来非常密切。
所以,只是为了好玩,假如我问你来计算结果
- 1/3 - 2/3 1/3
但是,您必须使用4位小数运算,首次近似每个数字4位十进制数。你将得到:
0.6667 - 0.3333 - 0.3333 = 0.0001
所以即使答案是数学零,当我们使用有限数量的任何形式的数字,结果不需要零。
秩序产生影响吗?
x =单(0.1 [0.2—0.3]);
x (3) - x (1) - (2)
ans =1.4901 e-08
——(x (1) + (2) + x (3)
ans =0
再次,从不信任的最低有效位的结果。实际上在这两种情况下,答案是零,在宽容的eps(“单身”)。
答案是学会使用公差。学会不相信那些最低有效位。从来没有测试完全平等的浮点数,至少直到你了解他们,你完全理解。
9日评论
沃尔特·罗伯森
沃尔特·罗伯森 2023年5月19日
注意通过高性能库的方式可能会有所不同取决于处理器,英特尔和AMD等。

登录置评。

答案(1)

詹姆斯Tursa
詹姆斯Tursa 2023年5月19日
编辑:詹姆斯Tursa 2023年5月22日
有些相关评论:
一般来说,BLAS / LAPACK库不包含混合类型参数的例程。例如,没有巴拉斯矩阵乘法程序用一个精度矩阵与一个双精度矩阵。完成这个例程与布拉斯必须首先做一个临时的副本单矩阵作为一个双矩阵,然后调用适当的布拉斯特区例行公事。这当然会消耗额外的时间和内存。唯一的例外是积累一些例程(例如,单精度的点积输入但使用双精度蓄电池)。话虽这么说,我不知道如果MATLAB利用这些额外的可用精密累加器例程。
相关,也没有真正的混合/复杂参数巴拉斯/ LAPACK库例程。所有参数都必须是真实的或所有参数都必须是复杂的。和所有的复杂的变量是假定为交叉存取内存模型(这是真的,甚至回到R2017b和早期)。
MATLAB R2017b和之前使用一个单独的复杂的内存模型,这意味着真正的变量在连续的记忆的一部分,是独立于虚部也在连续的内存。为MATLAB R2018a后来演变成交错复杂的内存模型,在实部与虚部是交叉在内存中。现在将更好的BLAS / LAPACK库和复杂的变量通常是如何在内存中其他语言如Fortran和C / c++,但对如何使用BLAS / LAPACK例程的背景。几个例子:
(真正的矩阵)*(复杂的矩阵)
R2017b:早些时候,可以实现这一系列的真正bla常规要求各个实部和虚部。不需要临时副本。
R2018a后来:这需要一个临时复制的矩阵作为交错复杂的矩阵与虚部0 bla常规可以使用这样的复杂。需要额外的时间和内存R2017b和同期相比,还有很多不必要的0繁殖将(这可能会让一些南结果不出现在R2017b如果有正相关)。
发票(复杂的矩阵)
R2017b:早些时候,这涉及到调用复杂LAPACK例程,所以单独的实部和虚部的变量必须先复制到一个等价的交叉变量。然后适当的LAPACK例程调用。然后交错的结果必须被复制到一个单独的内存模型变量。需要额外的时间和内存R2018b后来相比。
R2018b后来:这可以直接复杂LAPACK例程调用来完成。不需要临时副本。
Symmetrix矩阵结果:
一个=兰德(5000);
= ';%的转置构造在内存中
抽搐;x =“*;toc% Symmetrix矩阵乘法程序调用时,没有明确形成
运行时间是0.737080秒。
抽搐;在* y =;toc%的通用矩阵乘以常规使用显式地调用组成了一个“
运行时间是1.300470秒。
isequal (x, y)
ans =逻辑
1
isequal (x, x ')%严格对称的结果
ans =逻辑
1
isequal (y, y”)%可能不是严格对称的结果
ans =逻辑
1
这最后一个例子,你可以影响巴拉斯例程被称为在后台如何编写代码。必须注意保持严格的对称的结果。在“*,MATLAB可以识别输入和调用一个对称的对称性在后台程序没有明确形成了' A '。花费更少的时间和保证结果严格对称的结果。*一个例子,' A '明确形成但MATLAB在完全没有线索,转置,所以一个通用的矩阵乘以例程需要更长的时间,并不能保证一个严格对称的结果。在最后的情况下我们碰巧得到严格的对称性,但这将很大程度上取决于您的版本和MATLAB /布拉斯不能得到保证。
7评论
詹姆斯Tursa
詹姆斯Tursa 2023年5月23日
编辑:詹姆斯Tursa 2023年5月23日
所以我继续做这个测试,我预期,一个无效的结果。使用正确的墨西哥人代码:
> > =兰德(5000);
> > B =兰德(5000);
> > C = A * B;
> > Cmex = dgemm_inplace_test (A, B);
> > isequal (C, Cmex)
ans =
逻辑
1
用不正确的原地墨西哥人代码:
> > Cmex = dgemm_inplace_test (A, B);
> > isequal (C)%因为原地结果比较
ans =
逻辑
0
> > max (abs ((,) - c (:)))
ans =
1.1143 e + 27
这是代码,调用与方阵A和C的大小相同的原地测试:
/ /是否通用矩阵乘法使用巴拉斯dgemm ()
/ / C = A * B
/ *包括- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * /
#包括“mex.h”
#包括“blas.h”
/ *网关- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * /
无效mexFunction (int nlhs mxArray * plhs [], int nrhs, const mxArray * prhs [])
{
char TRANS =“N”;
mwSignedIndex M, N, K, LDA, LDB, LDC;
双* A * B * C;
双α= 1.0,β= 0.0;
如果(nlhs > 1)
mexErrMsgTxt (“太多的输出”。);
如果(nrhs ! = 2 | |! mxIsDouble (prhs [0]) | | ! mxIsDouble (prhs [1]) | |
mxIsSparse (prhs [0]) | | mxIsSparse (prhs [1]) | |
mxIsComplex (prhs [0]) | | mxIsComplex (prhs [1]) | |
mxGetNumberOfDimensions (prhs [0]) ! = 2 | | mxGetNumberOfDimensions (prhs [1]) ! = 2)
mexErrMsgTxt (“需要两个完整的双真正的二维矩阵输入。”);
M = mxGetM (prhs [0]);
K = mxGetN (prhs [0]);
N = mxGetN (prhs [1]);
LDA = M;
LDB = mxGetM (prhs [1]);
LDC = M;
一个= mxGetData (prhs [0]);
B = mxGetData (prhs [1]);
如果(LDB ! = K)
mexErrMsgTxt (“不正确的维度的矩阵乘法。”);
plhs [0] = mxCreateDoubleMatrix (M, N, mxREAL);
C = mxGetData (plhs [0]);
/ / dgemm(反式、反式a&m, n,,大部分α,A, lda, B . ldb,β,C, ldc);/ /正确的代码
dgemm(反式、反式a&m, n,大部分α,A, lda, B . ldb,β,A, ldc);/ /错误原地代码
}
编译使用这个helper函数:
函数compile_blas(变长度输入宗量)
libdir =“微软”;
lib_blas = fullfile (matlabroot,“外来的”,“自由”、计算机(“拱”)、libdir“libmwblas.lib”);
lib_blas,墨西哥人(变长度输入宗量{:}“-largeArrayDims”);
结束

登录置评。

下载188bet金宝搏


释放

R2019a

社区寻宝

找到宝藏在MATLAB中央,发现社区如何帮助你!

开始狩猎!